ts-packages 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.
- package/package.json +18 -0
- package/packages/response-utils/README.md +110 -0
- package/packages/response-utils/package.json +22 -0
- package/packages/response-utils/src/index.ts +168 -0
- package/packages/response-utils/tsconfig.json +21 -0
- package/packages/security/README.md +116 -0
- package/packages/security/package.json +30 -0
- package/packages/security/src/index.ts +39 -0
- package/packages/security/tsconfig.json +21 -0
- package/packages/server-utils/README.md +281 -0
- package/packages/server-utils/package.json +27 -0
- package/packages/server-utils/src/health.ts +47 -0
- package/packages/server-utils/src/index.ts +113 -0
- package/packages/server-utils/src/middleware.ts +275 -0
- package/packages/server-utils/src/server.ts +320 -0
- package/packages/server-utils/src/shutdown.ts +60 -0
- package/packages/server-utils/src/types.ts +64 -0
- package/packages/server-utils/src/utils.ts +34 -0
- package/packages/server-utils/tsconfig.json +21 -0
- package/pnpm-workspace.yaml +2 -0
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ts-packages",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"packageManager": "pnpm@10.20.0",
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"eslint": "^9.39.1",
|
|
15
|
+
"prettier": "^3.6.2",
|
|
16
|
+
"typescript": "^5.9.3"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @naman_deep_singh/response-utils
|
|
2
|
+
|
|
3
|
+
TypeScript utilities for standardized HTTP API responses with common status codes and error handling. Supports both standalone usage and Express.js integration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @naman_deep_singh/response-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ✅ **Standardized API responses** with consistent format
|
|
14
|
+
- ✅ **Express.js integration** - automatically sets HTTP status codes
|
|
15
|
+
- ✅ **TypeScript support** with full type safety
|
|
16
|
+
- ✅ **Hybrid exports** - use named imports or namespace imports
|
|
17
|
+
- ✅ **Pagination support** with metadata
|
|
18
|
+
- ✅ **Common HTTP status codes** (200, 201, 400, 401, 403, 404, 408, 409, 422, 429, 500)
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Named Imports (Tree-shakable)
|
|
23
|
+
```typescript
|
|
24
|
+
import { success, error, created, notFound, paginated } from '@naman_deep_singh/response-utils';
|
|
25
|
+
|
|
26
|
+
// Success responses
|
|
27
|
+
const userResponse = success({ id: 1, name: 'John' }, 'User found');
|
|
28
|
+
const createdResponse = created({ id: 2, name: 'Jane' });
|
|
29
|
+
|
|
30
|
+
// Error responses
|
|
31
|
+
const errorResponse = notFound('User not found');
|
|
32
|
+
const validationResponse = validationError('Invalid input', ['Name is required']);
|
|
33
|
+
|
|
34
|
+
// Paginated responses
|
|
35
|
+
const paginatedUsers = paginated([{id: 1}, {id: 2}], 1, 10, 25);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Namespace Import
|
|
39
|
+
```typescript
|
|
40
|
+
import ResponseUtils from '@naman_deep_singh/response-utils';
|
|
41
|
+
|
|
42
|
+
const response = ResponseUtils.success({ id: 1 }, 'Success');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Express.js Integration
|
|
46
|
+
```typescript
|
|
47
|
+
import { success, notFound } from '@naman_deep_singh/response-utils';
|
|
48
|
+
import { Request, Response } from 'express';
|
|
49
|
+
|
|
50
|
+
app.get('/users/:id', (req: Request, res: Response) => {
|
|
51
|
+
const user = findUser(req.params.id);
|
|
52
|
+
|
|
53
|
+
if (!user) {
|
|
54
|
+
return notFound('User not found', res); // Sets status 404 and sends response
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return success(user, 'User found', 200, res); // Sets status 200 and sends response
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API Reference
|
|
62
|
+
|
|
63
|
+
### Success Responses
|
|
64
|
+
- `success<T>(data: T, message?, statusCode?, res?)` - Generic success response (200)
|
|
65
|
+
- `created<T>(data: T, message?, res?)` - 201 Created response
|
|
66
|
+
- `noContent(message?, res?)` - 204 No Content response
|
|
67
|
+
- `paginated<T>(data: T[], page, limit, total, message?, res?)` - Paginated response with metadata
|
|
68
|
+
|
|
69
|
+
### Error Responses
|
|
70
|
+
- `error(message, statusCode?, error?, res?)` - Generic error response
|
|
71
|
+
- `badRequest(message?, validationError?, res?)` - 400 Bad Request
|
|
72
|
+
- `unauthorized(message?, res?)` - 401 Unauthorized
|
|
73
|
+
- `forbidden(message?, res?)` - 403 Forbidden
|
|
74
|
+
- `notFound(message?, res?)` - 404 Not Found
|
|
75
|
+
- `timeout(message?, res?)` - 408 Request Timeout
|
|
76
|
+
- `conflict(message?, res?)` - 409 Conflict
|
|
77
|
+
- `validationError(message?, errors[], res?)` - 422 Validation Error
|
|
78
|
+
- `tooManyRequests(message?, res?)` - 429 Too Many Requests
|
|
79
|
+
- `serverError(message?, res?)` - 500 Internal Server Error
|
|
80
|
+
|
|
81
|
+
### Utility Functions
|
|
82
|
+
- `logError(context: string, error: unknown)` - Structured error logging
|
|
83
|
+
- `getErrorMessage(error: unknown)` - Extract error message safely
|
|
84
|
+
|
|
85
|
+
## Response Format
|
|
86
|
+
|
|
87
|
+
All responses follow the `ApiResponse<T>` interface:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
interface ApiResponse<T = any> {
|
|
91
|
+
success: boolean;
|
|
92
|
+
message: string;
|
|
93
|
+
data?: T;
|
|
94
|
+
error?: string;
|
|
95
|
+
statusCode: number;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Paginated Response Format
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
103
|
+
pagination: {
|
|
104
|
+
page: number;
|
|
105
|
+
limit: number;
|
|
106
|
+
total: number;
|
|
107
|
+
totalPages: number;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@naman_deep_singh/response-utils",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "TypeScript utilities for standardized HTTP API responses with common status codes and error handling",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"response",
|
|
12
|
+
"http",
|
|
13
|
+
"api",
|
|
14
|
+
"utils"
|
|
15
|
+
],
|
|
16
|
+
"author": "Naman Deep Singh",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"packageManager": "pnpm@10.20.0",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"typescript": "^5.9.3"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
export interface ApiResponse<T = any> {
|
|
2
|
+
success: boolean;
|
|
3
|
+
message: string;
|
|
4
|
+
data?: T;
|
|
5
|
+
error?: string;
|
|
6
|
+
statusCode: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ResponseObject {
|
|
10
|
+
status: (code: number) => ResponseObject;
|
|
11
|
+
json: (data: unknown) => any;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const success = <T>(data: T, message = 'Success', statusCode = 200, res?: ResponseObject): ApiResponse<T> => {
|
|
15
|
+
const response = {
|
|
16
|
+
success: true,
|
|
17
|
+
message,
|
|
18
|
+
data,
|
|
19
|
+
statusCode
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (res) {
|
|
23
|
+
return res.status(statusCode).json(response);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return response;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const error = (message: string, statusCode = 500, error?: string, res?: ResponseObject): ApiResponse => {
|
|
30
|
+
const response = {
|
|
31
|
+
success: false,
|
|
32
|
+
message,
|
|
33
|
+
error,
|
|
34
|
+
statusCode
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (res) {
|
|
38
|
+
return res.status(statusCode).json(response);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return response;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const created = <T>(data: T, message = 'Created successfully', res?: ResponseObject): ApiResponse<T> =>
|
|
45
|
+
success(data, message, 201, res);
|
|
46
|
+
|
|
47
|
+
export const notFound = (message = 'Resource not found', res?: ResponseObject): ApiResponse =>
|
|
48
|
+
error(message, 404, undefined, res);
|
|
49
|
+
|
|
50
|
+
export const badRequest = (message = 'Bad request', validationError?: string, res?: ResponseObject): ApiResponse =>
|
|
51
|
+
error(message, 400, validationError, res);
|
|
52
|
+
|
|
53
|
+
export const unauthorized = (message = 'Unauthorized', res?: ResponseObject): ApiResponse =>
|
|
54
|
+
error(message, 401, undefined, res);
|
|
55
|
+
|
|
56
|
+
export const forbidden = (message = 'Forbidden', res?: ResponseObject): ApiResponse =>
|
|
57
|
+
error(message, 403, undefined, res);
|
|
58
|
+
|
|
59
|
+
export const serverError = (message = 'Internal server error', res?: ResponseObject): ApiResponse =>
|
|
60
|
+
error(message, 500, undefined, res);
|
|
61
|
+
|
|
62
|
+
export const noContent = (message = 'No content', res?: ResponseObject): ApiResponse => {
|
|
63
|
+
const response = {
|
|
64
|
+
success: true,
|
|
65
|
+
message,
|
|
66
|
+
statusCode: 204
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
if (res) {
|
|
70
|
+
return res.status(204).json(response);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return response;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const conflict = (message = 'Conflict', res?: ResponseObject): ApiResponse =>
|
|
77
|
+
error(message, 409, undefined, res);
|
|
78
|
+
|
|
79
|
+
export const validationError = (message = 'Validation failed', errors: string[], res?: ResponseObject): ApiResponse => {
|
|
80
|
+
const response = {
|
|
81
|
+
success: false,
|
|
82
|
+
message,
|
|
83
|
+
error: errors.join(', '),
|
|
84
|
+
statusCode: 422
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
if (res) {
|
|
88
|
+
return res.status(422).json(response);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return response;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
95
|
+
pagination: {
|
|
96
|
+
page: number;
|
|
97
|
+
limit: number;
|
|
98
|
+
total: number;
|
|
99
|
+
totalPages: number;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const paginated = <T>(
|
|
104
|
+
data: T[],
|
|
105
|
+
page: number,
|
|
106
|
+
limit: number,
|
|
107
|
+
total: number,
|
|
108
|
+
message = 'Data retrieved successfully',
|
|
109
|
+
res?: ResponseObject
|
|
110
|
+
): PaginatedResponse<T> => {
|
|
111
|
+
const response = {
|
|
112
|
+
success: true,
|
|
113
|
+
message,
|
|
114
|
+
data,
|
|
115
|
+
statusCode: 200,
|
|
116
|
+
pagination: {
|
|
117
|
+
page,
|
|
118
|
+
limit,
|
|
119
|
+
total,
|
|
120
|
+
totalPages: Math.ceil(total / limit)
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
if (res) {
|
|
125
|
+
return res.status(200).json(response);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return response;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const tooManyRequests = (message = 'Too many requests', res?: ResponseObject): ApiResponse =>
|
|
132
|
+
error(message, 429, undefined, res);
|
|
133
|
+
|
|
134
|
+
export const timeout = (message = 'Request timeout', res?: ResponseObject): ApiResponse =>
|
|
135
|
+
error(message, 408, undefined, res);
|
|
136
|
+
|
|
137
|
+
export const logError = (context: string, error: unknown): void => {
|
|
138
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
139
|
+
console.error(`Error in ${context}:`, message);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const getErrorMessage = (error: unknown): string => {
|
|
143
|
+
if (error instanceof Error) return error.message;
|
|
144
|
+
if (typeof error === 'string') return error;
|
|
145
|
+
return 'An unknown error occurred';
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Default export for namespace usage
|
|
149
|
+
const ResponseUtils = {
|
|
150
|
+
success,
|
|
151
|
+
error,
|
|
152
|
+
created,
|
|
153
|
+
notFound,
|
|
154
|
+
badRequest,
|
|
155
|
+
unauthorized,
|
|
156
|
+
forbidden,
|
|
157
|
+
serverError,
|
|
158
|
+
noContent,
|
|
159
|
+
conflict,
|
|
160
|
+
validationError,
|
|
161
|
+
paginated,
|
|
162
|
+
tooManyRequests,
|
|
163
|
+
timeout,
|
|
164
|
+
logError,
|
|
165
|
+
getErrorMessage
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export default ResponseUtils;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"baseUrl": ".",
|
|
15
|
+
"paths": {
|
|
16
|
+
"*": ["*", "*.ts", "*.js"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# @naman_deep_singh/security
|
|
2
|
+
|
|
3
|
+
Security utilities for password hashing and JWT token management with TypeScript support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @naman_deep_singh/security
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ✅ **Password hashing** with bcrypt (salt rounds: 10)
|
|
14
|
+
- ✅ **JWT token management** with configurable expiration
|
|
15
|
+
- ✅ **TypeScript support** with full type safety
|
|
16
|
+
- ✅ **Hybrid exports** - use named imports or namespace imports
|
|
17
|
+
- ✅ **Backward compatibility** with legacy function names
|
|
18
|
+
- ✅ **Async/await support** for all operations
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Named Imports (Tree-shakable)
|
|
23
|
+
```typescript
|
|
24
|
+
import { hashPassword, verifyPassword, generateToken, verifyToken } from '@naman_deep_singh/security';
|
|
25
|
+
|
|
26
|
+
// Password hashing
|
|
27
|
+
const hashedPassword = await hashPassword('mypassword');
|
|
28
|
+
const isValid = await verifyPassword('mypassword', hashedPassword);
|
|
29
|
+
|
|
30
|
+
// JWT tokens
|
|
31
|
+
const token = generateToken({ userId: 1, role: 'admin' }, 'your-secret-key', '24h');
|
|
32
|
+
const decoded = verifyToken(token, 'your-secret-key');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Namespace Import
|
|
36
|
+
```typescript
|
|
37
|
+
import SecurityUtils from '@naman_deep_singh/security';
|
|
38
|
+
|
|
39
|
+
const hashedPassword = await SecurityUtils.hashPassword('mypassword');
|
|
40
|
+
const token = SecurityUtils.generateToken({ userId: 1 }, 'secret');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Backward Compatibility
|
|
44
|
+
```typescript
|
|
45
|
+
import { comparePassword, signToken } from '@naman_deep_singh/security';
|
|
46
|
+
|
|
47
|
+
// Legacy function names still work
|
|
48
|
+
const isValid = await comparePassword('password', 'hash');
|
|
49
|
+
const token = signToken({ userId: 1 }, 'secret');
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API Reference
|
|
53
|
+
|
|
54
|
+
### Password Functions
|
|
55
|
+
- `hashPassword(password: string): Promise<string>` - Hash a password using bcrypt with salt rounds 10
|
|
56
|
+
- `verifyPassword(password: string, hash: string): Promise<boolean>` - Verify password against hash
|
|
57
|
+
- `comparePassword(password: string, hash: string): Promise<boolean>` - Alias for verifyPassword (backward compatibility)
|
|
58
|
+
|
|
59
|
+
### JWT Functions
|
|
60
|
+
- `generateToken(payload: Record<string, unknown>, secret: Secret, expiresIn?: string): string` - Generate JWT token
|
|
61
|
+
- `verifyToken(token: string, secret: Secret): string | JwtPayload` - Verify and decode JWT token
|
|
62
|
+
- `signToken(payload: Record<string, unknown>, secret: Secret, expiresIn?: string): string` - Alias for generateToken (backward compatibility)
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
|
|
66
|
+
### Complete Authentication Flow
|
|
67
|
+
```typescript
|
|
68
|
+
import { hashPassword, verifyPassword, generateToken, verifyToken } from '@naman_deep_singh/security';
|
|
69
|
+
|
|
70
|
+
// Registration
|
|
71
|
+
async function registerUser(email: string, password: string) {
|
|
72
|
+
const hashedPassword = await hashPassword(password);
|
|
73
|
+
// Save user with hashedPassword to database
|
|
74
|
+
return { email, password: hashedPassword };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Login
|
|
78
|
+
async function loginUser(email: string, password: string, storedHash: string) {
|
|
79
|
+
const isValid = await verifyPassword(password, storedHash);
|
|
80
|
+
|
|
81
|
+
if (!isValid) {
|
|
82
|
+
throw new Error('Invalid credentials');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const token = generateToken(
|
|
86
|
+
{ email, loginTime: Date.now() },
|
|
87
|
+
process.env.JWT_SECRET!,
|
|
88
|
+
'7d'
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return { token };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Verify JWT
|
|
95
|
+
function authenticateRequest(token: string) {
|
|
96
|
+
try {
|
|
97
|
+
const decoded = verifyToken(token, process.env.JWT_SECRET!);
|
|
98
|
+
return decoded;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
throw new Error('Invalid token');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Dependencies
|
|
106
|
+
|
|
107
|
+
- **bcryptjs** - For secure password hashing
|
|
108
|
+
- **jsonwebtoken** - For JWT token management
|
|
109
|
+
|
|
110
|
+
## Security Best Practices
|
|
111
|
+
|
|
112
|
+
1. **Use strong secrets** for JWT signing (minimum 32 characters)
|
|
113
|
+
2. **Set appropriate expiration times** for tokens
|
|
114
|
+
3. **Store JWT secrets in environment variables**
|
|
115
|
+
4. **Never log or expose hashed passwords**
|
|
116
|
+
5. **Use HTTPS** in production for token transmission
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@naman_deep_singh/security",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Security utilities for password hashing and JWT token management with TypeScript",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"security",
|
|
12
|
+
"jwt",
|
|
13
|
+
"bcrypt",
|
|
14
|
+
"authentication",
|
|
15
|
+
"password",
|
|
16
|
+
"token"
|
|
17
|
+
],
|
|
18
|
+
"author": "Naman Deep Singh",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"packageManager": "pnpm@10.20.0",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"bcryptjs": "^3.0.3",
|
|
23
|
+
"jsonwebtoken": "^9.0.2"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/bcryptjs": "^2.4.6",
|
|
27
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
28
|
+
"typescript": "^5.9.3"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import jwt, { Secret, JwtPayload } from "jsonwebtoken";
|
|
2
|
+
import bcrypt from "bcryptjs";
|
|
3
|
+
|
|
4
|
+
// 🧱 Password helpers
|
|
5
|
+
export const hashPassword = async (password: string): Promise<string> => {
|
|
6
|
+
const salt = await bcrypt.genSalt(10);
|
|
7
|
+
return bcrypt.hash(password, salt);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const verifyPassword = async (password: string, hash: string): Promise<boolean> => {
|
|
11
|
+
return bcrypt.compare(password, hash);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// For backward compatibility
|
|
15
|
+
export const comparePassword = verifyPassword;
|
|
16
|
+
|
|
17
|
+
// 🧩 JWT helpers
|
|
18
|
+
export const generateToken = (payload: Record<string, unknown>, secret: Secret, expiresIn = "1h"): string => {
|
|
19
|
+
return jwt.sign(payload, secret, { expiresIn, algorithm: "HS256" } as jwt.SignOptions);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const verifyToken = (token: string, secret: Secret): string | JwtPayload => {
|
|
23
|
+
return jwt.verify(token, secret);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// For backward compatibility
|
|
27
|
+
export const signToken = generateToken;
|
|
28
|
+
|
|
29
|
+
// Default export for namespace usage
|
|
30
|
+
const SecurityUtils = {
|
|
31
|
+
hashPassword,
|
|
32
|
+
verifyPassword,
|
|
33
|
+
comparePassword,
|
|
34
|
+
generateToken,
|
|
35
|
+
verifyToken,
|
|
36
|
+
signToken
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default SecurityUtils;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"baseUrl": ".",
|
|
15
|
+
"paths": {
|
|
16
|
+
"*": ["*", "*.ts", "*.js"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist"]
|
|
21
|
+
}
|