create-express-mongo-ts 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.
Files changed (54) hide show
  1. package/README.md +157 -0
  2. package/bin/cli.js +217 -0
  3. package/package.json +43 -0
  4. package/template/.dockerignore +2 -0
  5. package/template/.prettierignore +6 -0
  6. package/template/.prettierrc +8 -0
  7. package/template/Dockerfile +17 -0
  8. package/template/README.md +67 -0
  9. package/template/eslint.config.mts +34 -0
  10. package/template/jest.config.ts +201 -0
  11. package/template/keys/README.md +2 -0
  12. package/template/nodemon.json +5 -0
  13. package/template/package.json +65 -0
  14. package/template/src/app.ts +42 -0
  15. package/template/src/config.ts +31 -0
  16. package/template/src/core/ApiError.ts +118 -0
  17. package/template/src/core/ApiResponse.ts +140 -0
  18. package/template/src/core/asyncHandler.ts +15 -0
  19. package/template/src/core/authUtils.ts +68 -0
  20. package/template/src/core/jwtUtils.ts +96 -0
  21. package/template/src/core/logger.ts +48 -0
  22. package/template/src/core/utils.ts +12 -0
  23. package/template/src/database/index.ts +56 -0
  24. package/template/src/database/models/ApiKeys.ts +62 -0
  25. package/template/src/database/models/Keystore.ts +45 -0
  26. package/template/src/database/models/Role.ts +27 -0
  27. package/template/src/database/models/User.ts +64 -0
  28. package/template/src/database/repositories/ApiKeyRepo.ts +26 -0
  29. package/template/src/database/repositories/KeystoreRepo.ts +53 -0
  30. package/template/src/database/repositories/UserRepo.ts +63 -0
  31. package/template/src/helpers/generateApiKey.ts +23 -0
  32. package/template/src/helpers/validator.ts +38 -0
  33. package/template/src/index.ts +36 -0
  34. package/template/src/middlewares/authorize.middleware.ts +26 -0
  35. package/template/src/middlewares/error.middleware.ts +42 -0
  36. package/template/src/middlewares/permission.middleware.ts +20 -0
  37. package/template/src/middlewares/validator.middleware.ts +170 -0
  38. package/template/src/routes/auth/apiKey.ts +29 -0
  39. package/template/src/routes/auth/authentication.ts +45 -0
  40. package/template/src/routes/auth/index.ts +14 -0
  41. package/template/src/routes/auth/schema.ts +34 -0
  42. package/template/src/routes/auth/signin.ts +47 -0
  43. package/template/src/routes/auth/signout.ts +20 -0
  44. package/template/src/routes/auth/signup.ts +49 -0
  45. package/template/src/routes/auth/token.ts +68 -0
  46. package/template/src/routes/health/index.ts +14 -0
  47. package/template/src/routes/index.ts +19 -0
  48. package/template/src/types/ApiKey.ts +13 -0
  49. package/template/src/types/Keystore.ts +12 -0
  50. package/template/src/types/Role.ts +14 -0
  51. package/template/src/types/User.ts +16 -0
  52. package/template/src/types/app-requests.d.ts +22 -0
  53. package/template/src/types/permissions.ts +3 -0
  54. package/template/tsconfig.json +33 -0
@@ -0,0 +1,42 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import logger from './../core/logger.js';
3
+ import { isProduction } from './../config.js';
4
+ import { ApiError, ErrorType } from './../core/ApiError.js';
5
+
6
+ export const errorHandler = (
7
+ err: Error,
8
+ req: Request,
9
+ res: Response,
10
+ _next: NextFunction,
11
+ ) => {
12
+ let statusCode = 500;
13
+ let message = 'Something went wrong';
14
+ const errors: string[] = [];
15
+
16
+ logger.error('Error:', {
17
+ error: err,
18
+ });
19
+
20
+ if (err instanceof ApiError) {
21
+ ApiError.handle(err, res);
22
+ if (err.type === ErrorType.INTERNAL)
23
+ logger.error(
24
+ `500 - ${err.message} - ${req.originalUrl} - ${req.method} - ${req.ip}`,
25
+ );
26
+ return;
27
+ }
28
+
29
+ if (!isProduction) {
30
+ message = err?.message || message;
31
+ errors.push(err?.message);
32
+ }
33
+
34
+ res.status(statusCode).json({
35
+ success: false,
36
+ statusCode,
37
+ message,
38
+ ...(errors.length > 0 && !isProduction && { errors }),
39
+ timeStamp: new Date().toISOString(),
40
+ path: req.originalUrl,
41
+ });
42
+ };
@@ -0,0 +1,20 @@
1
+ import { Response, NextFunction } from 'express';
2
+ import { ForbiddenError } from '../core/ApiError';
3
+ import { PublicRequest } from '../types/app-requests';
4
+
5
+ export default (permission: string) =>
6
+ (req: PublicRequest, _res: Response, next: NextFunction) => {
7
+ try {
8
+ if (!req.apiKey?.permissions)
9
+ return next(new ForbiddenError('Permission Denied'));
10
+
11
+ const exists = req.apiKey.permissions.find(
12
+ (entry) => entry === permission,
13
+ );
14
+ if (!exists) return next(new ForbiddenError('Permission Denied'));
15
+
16
+ next();
17
+ } catch (error) {
18
+ next(error);
19
+ }
20
+ };
@@ -0,0 +1,170 @@
1
+ import { RequestHandler } from 'express';
2
+ import { ZodSchema } from 'zod';
3
+
4
+ import { BadRequestError } from './../core/ApiError';
5
+ import { isProduction } from '../config.js';
6
+ import { ValidationSource } from './../helpers/validator';
7
+
8
+ type ValidationErrorDetail = {
9
+ field: string;
10
+ message: string;
11
+ value?: unknown;
12
+ };
13
+
14
+ const formatFieldName = (path: (string | number)[]): string => {
15
+ if (path.length === 0) return 'body';
16
+
17
+ return path
18
+ .map((segment, index) => {
19
+ if (typeof segment === 'number') {
20
+ return `[${segment}]`;
21
+ }
22
+ // Convert camelCase to readable format
23
+ const readable = segment.replace(/([A-Z])/g, ' $1').toLowerCase();
24
+ return index === 0 ? readable : segment;
25
+ })
26
+ .join('.');
27
+ };
28
+
29
+ const getReadableErrorMessage = (
30
+ code: string,
31
+ path: (string | number)[],
32
+ message: string,
33
+ received?: unknown,
34
+ expected?: string[],
35
+ ): string => {
36
+ const fieldName = formatFieldName(path);
37
+
38
+ switch (code) {
39
+ case 'invalid_type':
40
+ if (received === 'undefined' || received === 'null') {
41
+ return `${fieldName} is required`;
42
+ }
43
+ return `${fieldName} must be a valid ${expected}`;
44
+
45
+ case 'invalid_string':
46
+ if (message.includes('email')) {
47
+ return `${fieldName} must be a valid email address`;
48
+ }
49
+ if (message.includes('url')) {
50
+ return `${fieldName} must be a valid URL`;
51
+ }
52
+ if (message.includes('uuid')) {
53
+ return `${fieldName} must be a valid UUID`;
54
+ }
55
+ return `${fieldName} format is invalid`;
56
+
57
+ case 'too_small':
58
+ if (message.includes('String')) {
59
+ const minMatch = message.match(/at least (\d+)/);
60
+ const min = minMatch ? minMatch[1] : 'minimum';
61
+ return `${fieldName} must be at least ${min} characters long`;
62
+ }
63
+ if (message.includes('Number')) {
64
+ const minMatch = message.match(
65
+ /greater than or equal to (\d+)/,
66
+ );
67
+ const min = minMatch ? minMatch[1] : 'minimum value';
68
+ return `${fieldName} must be greater than or equal to ${min}`;
69
+ }
70
+ if (message.includes('Array')) {
71
+ const minMatch = message.match(/at least (\d+)/);
72
+ const min = minMatch ? minMatch[1] : 'minimum';
73
+ return `${fieldName} must contain at least ${min} item(s)`;
74
+ }
75
+ return message;
76
+
77
+ case 'too_big':
78
+ if (message.includes('String')) {
79
+ const maxMatch = message.match(/at most (\d+)/);
80
+ const max = maxMatch ? maxMatch[1] : 'maximum';
81
+ return `${fieldName} must be at most ${max} characters long`;
82
+ }
83
+ if (message.includes('Number')) {
84
+ const maxMatch = message.match(/less than or equal to (\d+)/);
85
+ const max = maxMatch ? maxMatch[1] : 'maximum value';
86
+ return `${fieldName} must be less than or equal to ${max}`;
87
+ }
88
+ if (message.includes('Array')) {
89
+ const maxMatch = message.match(/at most (\d+)/);
90
+ const max = maxMatch ? maxMatch[1] : 'maximum';
91
+ return `${fieldName} must contain at most ${max} item(s)`;
92
+ }
93
+ return message;
94
+
95
+ case 'invalid_enum_value':
96
+ const options = expected?.join(', ') || 'valid options';
97
+ return `${fieldName} must be one of: ${options}`;
98
+
99
+ case 'unrecognized_keys':
100
+ const keys = message.match(
101
+ /Unrecognized key\(s\) in object: (.+)/,
102
+ )?.[1];
103
+ return keys
104
+ ? `Unexpected field(s): ${keys}`
105
+ : 'Unexpected fields in request';
106
+
107
+ case 'invalid_date':
108
+ return `${fieldName} must be a valid date`;
109
+
110
+ case 'invalid_literal':
111
+ return `${fieldName} must be exactly ${expected}`;
112
+
113
+ case 'custom':
114
+ return message; // Custom error messages are already descriptive
115
+
116
+ default:
117
+ return message || `${fieldName} is invalid`;
118
+ }
119
+ };
120
+
121
+ type ZodSafeError = {
122
+ path: string[];
123
+ code: string;
124
+ message: string;
125
+ expected: string[];
126
+ };
127
+
128
+ export const validator = (
129
+ schema: ZodSchema,
130
+ source: ValidationSource,
131
+ ): RequestHandler => {
132
+ return (req, _res, next): void => {
133
+ const result = schema.safeParse(req[source]);
134
+
135
+ if (!result.success) {
136
+ const errors: ZodSafeError[] = JSON.parse(String(result.error));
137
+ const validationErrors: ValidationErrorDetail[] = errors.map(
138
+ (err: {
139
+ path: string[];
140
+ code: string;
141
+ message: string;
142
+ expected: string[];
143
+ }) => ({
144
+ field: formatFieldName(err.path),
145
+ message: getReadableErrorMessage(
146
+ err.code,
147
+ err.path,
148
+ err.message,
149
+ 'received' in err ? err.received : undefined,
150
+ 'expected' in err ? err.expected : undefined,
151
+ ),
152
+ ...(!isProduction && {
153
+ value: err.path.reduce(
154
+ (obj: Record<string, unknown>, key: string | number) => obj?.[key],
155
+ req.body,
156
+ ),
157
+ }),
158
+ }),
159
+ );
160
+
161
+ const mainMessage =
162
+ validationErrors.length === 1
163
+ ? validationErrors[0].message
164
+ : `Validation failed for ${validationErrors.length} field(s)`;
165
+
166
+ return next(new BadRequestError(mainMessage));
167
+ }
168
+ next();
169
+ };
170
+ };
@@ -0,0 +1,29 @@
1
+ import { Response, NextFunction } from 'express';
2
+ import schema from './schema';
3
+ import { validator } from './../../middlewares/validator.middleware';
4
+ import { ValidationSource } from '../../helpers/validator';
5
+ import { asyncHandler } from './../../core/asyncHandler';
6
+ import { PublicRequest } from './../../types/app-requests';
7
+ import { ForbiddenError } from './../../core/ApiError';
8
+ import { Header } from './../../core/utils';
9
+ import ApiKeyRepo from './../../database/repositories/ApiKeyRepo';
10
+
11
+ export const apiKeyMiddleware = [
12
+ validator(schema.apiKey, ValidationSource.HEADER),
13
+
14
+ asyncHandler<PublicRequest>(
15
+ async (req: PublicRequest, _res: Response, next: NextFunction) => {
16
+ const key = req.headers[Header.API_KEY]?.toString();
17
+
18
+ if (!key) throw new ForbiddenError('Missing API Key');
19
+
20
+ const apiKey = await ApiKeyRepo.findByKey(key);
21
+
22
+ if (!apiKey) throw new ForbiddenError('Invalid API Key');
23
+
24
+ req.apiKey = apiKey;
25
+
26
+ next();
27
+ },
28
+ ),
29
+ ];
@@ -0,0 +1,45 @@
1
+ import { Router } from 'express';
2
+ import { validator } from '../../middlewares/validator.middleware';
3
+ import schema from './schema';
4
+ import { ValidationSource } from '../../helpers/validator';
5
+ import { asyncHandler } from '../../core/asyncHandler';
6
+ import { ProtectedRequest } from '../../types/app-requests';
7
+ import { getAccessToken, validateTokenData } from '../../core/authUtils';
8
+ import { TokenExpiredError } from 'jsonwebtoken';
9
+ import { AccessTokenError, AuthFailureError } from '../../core/ApiError';
10
+ import jwtUtils from '../../core/jwtUtils';
11
+ import UserRepo from '../../database/repositories/UserRepo';
12
+ import { Types } from 'mongoose';
13
+ import KeystoreRepo from '../../database/repositories/KeystoreRepo';
14
+ const router = Router();
15
+
16
+ export default router.use(
17
+ validator(schema.auth, ValidationSource.HEADER),
18
+ asyncHandler(async (req: ProtectedRequest, _res, next) => {
19
+ req.accessToken = getAccessToken(req.headers.authorization);
20
+
21
+ try {
22
+ const payload = await jwtUtils.validate(req.accessToken);
23
+ validateTokenData(payload);
24
+
25
+ const user = await UserRepo.findById(
26
+ new Types.ObjectId(payload.sub),
27
+ );
28
+ if (!user) throw new AuthFailureError('User not registered.');
29
+ req.user = user;
30
+
31
+ const keystore = await KeystoreRepo.findForKey(
32
+ req.user,
33
+ payload.prm,
34
+ );
35
+ if (!keystore) throw new AuthFailureError('Invalid access token.');
36
+ req.keystore = keystore;
37
+
38
+ return next();
39
+ } catch (e) {
40
+ if (e instanceof TokenExpiredError)
41
+ throw new AccessTokenError(e.message);
42
+ throw e;
43
+ }
44
+ }),
45
+ );
@@ -0,0 +1,14 @@
1
+ import { Router } from 'express';
2
+ import signupRoute from './signup';
3
+ import signinRoute from './signin';
4
+ import signoutRoute from './signout';
5
+ import refreshTokenRouter from './token';
6
+
7
+ const router = Router();
8
+
9
+ router.use('/signup', signupRoute);
10
+ router.use('/signin', signinRoute);
11
+ router.use('/signout', signoutRoute);
12
+ router.use('/token', refreshTokenRouter);
13
+
14
+ export default router;
@@ -0,0 +1,34 @@
1
+ import { Header } from './../../core/utils';
2
+ import { ZodAuthBearer } from './../../helpers/validator';
3
+ import z from 'zod';
4
+
5
+ const apiKey = z.object({
6
+ [Header.API_KEY]: z.string(),
7
+ });
8
+
9
+ const auth = z.object({
10
+ authorization: ZodAuthBearer,
11
+ });
12
+
13
+ const signup = z.object({
14
+ name: z.string().min(3),
15
+ email: z.email(),
16
+ password: z.string().min(6),
17
+ });
18
+
19
+ const signin = z.object({
20
+ email: z.email(),
21
+ password: z.string().min(6),
22
+ });
23
+
24
+ const refreshToken = z.object({
25
+ refreshToken: z.string().min(1)
26
+ });
27
+
28
+ export default {
29
+ apiKey,
30
+ auth,
31
+ signup,
32
+ signin,
33
+ refreshToken
34
+ };
@@ -0,0 +1,47 @@
1
+ import { asyncHandler } from '../../core/asyncHandler';
2
+ import { Router } from 'express';
3
+ import { validator } from '../../middlewares/validator.middleware';
4
+ import schema from './schema';
5
+ import { PublicRequest } from '../../types/app-requests';
6
+ import UserRepo from '../../database/repositories/UserRepo';
7
+ import { AuthFailureError, BadRequestError } from '../../core/ApiError';
8
+ import crypto from 'crypto';
9
+ import KeystoreRepo from '../../database/repositories/KeystoreRepo';
10
+ import { createTokens, isPasswordCorrect } from '../../core/authUtils';
11
+ import { getUserData } from '../../core/utils';
12
+ import { SuccessResponse } from '../../core/ApiResponse';
13
+ import { ValidationSource } from '../../helpers/validator';
14
+
15
+ const router = Router();
16
+
17
+ router.post(
18
+ '/',
19
+ validator(schema.signin, ValidationSource.BODY),
20
+ asyncHandler(async (req: PublicRequest, res) => {
21
+ const user = await UserRepo.findByEmail(req.body.email);
22
+
23
+ if (!user) throw new BadRequestError('User not registered.');
24
+
25
+ const isValid = await isPasswordCorrect(req.body.password, user.password);
26
+
27
+ if (!isValid) throw new AuthFailureError('Authentication failure.');
28
+
29
+ const accessTokenKey = crypto.randomBytes(64).toString('hex');
30
+ const refreshTokenKey = crypto.randomBytes(64).toString('hex');
31
+
32
+ await KeystoreRepo.create(user, accessTokenKey, refreshTokenKey);
33
+ const tokens = await createTokens(
34
+ user,
35
+ accessTokenKey,
36
+ refreshTokenKey,
37
+ );
38
+ const userData = getUserData(user);
39
+
40
+ new SuccessResponse('Login success.', {
41
+ user: userData,
42
+ tokens: tokens,
43
+ }).send(res);
44
+ }),
45
+ );
46
+
47
+ export default router;
@@ -0,0 +1,20 @@
1
+ import { SuccessMsgResponse } from '../../core/ApiResponse';
2
+ import { asyncHandler } from '../../core/asyncHandler';
3
+ import KeystoreRepo from '../../database/repositories/KeystoreRepo';
4
+ import { Router } from 'express';
5
+ import authentication from './authentication';
6
+ import { ProtectedRequest } from '../../types/app-requests';
7
+
8
+ const router = Router();
9
+
10
+ router.use(authentication);
11
+
12
+ router.delete(
13
+ '/',
14
+ asyncHandler(async (req: ProtectedRequest, res) => {
15
+ await KeystoreRepo.remove(req.keystore._id);
16
+ new SuccessMsgResponse('Logout Success').send(res);
17
+ }),
18
+ );
19
+
20
+ export default router;
@@ -0,0 +1,49 @@
1
+ import { Router } from 'express';
2
+ import { validator } from '../../middlewares/validator.middleware';
3
+ import schema from './schema';
4
+ import { asyncHandler } from './../../core/asyncHandler';
5
+ import UserRepo from '../../database/repositories/UserRepo';
6
+ import { BadRequestError } from '../../core/ApiError';
7
+ import crypto from 'crypto';
8
+ import User from './../../types/User';
9
+ import { createTokens } from '../../core/authUtils';
10
+ import { getUserData } from './../../core/utils';
11
+ import { SuccessResponse } from './../../core/ApiResponse';
12
+ import { RoleCode } from './../../types/Role';
13
+ import { ValidationSource } from '../../helpers/validator';
14
+
15
+ const router = Router();
16
+
17
+ router.post(
18
+ '/',
19
+ validator(schema.signup, ValidationSource.BODY),
20
+ asyncHandler(async (req, res) => {
21
+ const user = await UserRepo.findByEmail(req.body.email);
22
+ if (user) throw new BadRequestError('User already registered.');
23
+
24
+ const accessTokenKey = crypto.randomBytes(64).toString('hex');
25
+ const refreshTokenKey = crypto.randomBytes(64).toString('hex');
26
+
27
+ const { user: createdUser, keystore } = await UserRepo.create(
28
+ req.body as User,
29
+ accessTokenKey,
30
+ refreshTokenKey,
31
+ RoleCode.USER,
32
+ );
33
+
34
+ const tokens = await createTokens(
35
+ createdUser,
36
+ keystore.primaryKey,
37
+ keystore.secondaryKey,
38
+ );
39
+
40
+ const userData = getUserData(createdUser);
41
+
42
+ new SuccessResponse('Signup successful.', {
43
+ user: userData,
44
+ tokens: tokens,
45
+ }).send(res);
46
+ }),
47
+ );
48
+
49
+ export default router;
@@ -0,0 +1,68 @@
1
+ import { Router } from 'express';
2
+ import { validator } from '../../middlewares/validator.middleware';
3
+ import schema from './schema';
4
+ import { ValidationSource } from '../../helpers/validator';
5
+ import { asyncHandler } from '../../core/asyncHandler';
6
+ import { ProtectedRequest } from '../../types/app-requests';
7
+ import { getAccessToken } from '../../core/authUtils';
8
+ import JWT from './../../core/jwtUtils';
9
+ import { validateTokenData, createTokens } from './../../core/authUtils';
10
+ import UserRepo from '../../database/repositories/UserRepo';
11
+ import KeystoreRepo from '../../database/repositories/KeystoreRepo';
12
+ import { Types } from 'mongoose';
13
+ import { AuthFailureError } from '../../core/ApiError';
14
+ import crypto from 'crypto';
15
+ import { TokenRefreshResponse } from '../../core/ApiResponse';
16
+ const router = Router();
17
+
18
+ router.post(
19
+ '/refresh',
20
+ validator(schema.auth, ValidationSource.HEADER),
21
+ validator(schema.refreshToken, ValidationSource.BODY),
22
+ asyncHandler(async (req: ProtectedRequest, res) => {
23
+ req.accessToken = getAccessToken(req.headers?.authorization);
24
+
25
+ const accessTokenPayload = await JWT.decode(req.accessToken);
26
+ validateTokenData(accessTokenPayload);
27
+
28
+ const user = await UserRepo.findById(
29
+ new Types.ObjectId(accessTokenPayload.sub),
30
+ );
31
+
32
+ if (!user) throw new AuthFailureError('User not registered');
33
+ req.user = user;
34
+
35
+ const refreshTokenPayload = await JWT.validate(req.body.refreshToken);
36
+ validateTokenData(refreshTokenPayload);
37
+
38
+ if (accessTokenPayload.sub !== refreshTokenPayload.sub)
39
+ throw new AuthFailureError('Invalid access token');
40
+
41
+ const keystore = await KeystoreRepo.find(
42
+ req.user,
43
+ accessTokenPayload.prm,
44
+ refreshTokenPayload.prm,
45
+ );
46
+
47
+ if (!keystore) throw new AuthFailureError('Invalid access token');
48
+ await KeystoreRepo.remove(keystore._id);
49
+
50
+ const accessTokenKey = crypto.randomBytes(64).toString('hex');
51
+ const refreshTokenKey = crypto.randomBytes(64).toString('hex');
52
+
53
+ await KeystoreRepo.create(req.user, accessTokenKey, refreshTokenKey);
54
+ const tokens = await createTokens(
55
+ req.user,
56
+ accessTokenKey,
57
+ refreshTokenKey,
58
+ );
59
+
60
+ new TokenRefreshResponse(
61
+ 'Token Issued',
62
+ tokens.accessToken,
63
+ tokens.refreshToken,
64
+ ).send(res);
65
+ }),
66
+ );
67
+
68
+ export default router;
@@ -0,0 +1,14 @@
1
+ import { SuccessMsgResponse } from '../../core/ApiResponse';
2
+ import { Router } from 'express';
3
+
4
+ const router = Router();
5
+
6
+ router.get('/', async (_req, res) => {
7
+ new SuccessMsgResponse('Sample API server is running.').send(res);
8
+ });
9
+
10
+ router.get('/health', async (_req, res) => {
11
+ new SuccessMsgResponse('The server is healthy and running.').send(res);
12
+ });
13
+
14
+ export default router;
@@ -0,0 +1,19 @@
1
+ import { Router, RequestHandler } from 'express';
2
+
3
+ import healthRoutes from "./health/index.js";
4
+ import { apiKeyMiddleware } from './auth/apiKey.js';
5
+ import permission from '../middlewares/permission.middleware.js';
6
+ import { Permission } from './../types/permissions';
7
+ import authRoutes from "./auth";
8
+
9
+ const router = Router();
10
+
11
+ router.use('/', healthRoutes);
12
+
13
+ router.use(apiKeyMiddleware);
14
+
15
+ router.use(permission(Permission.GENERAL) as RequestHandler);
16
+
17
+ router.use('/auth', authRoutes);
18
+
19
+ export default router;
@@ -0,0 +1,13 @@
1
+ import { Types } from "mongoose";
2
+ import { Permission } from "./permissions";
3
+
4
+ export default interface ApiKey {
5
+ _id: Types.ObjectId;
6
+ key: string;
7
+ version: number;
8
+ permissions: Permission[];
9
+ comments: string[];
10
+ status?: boolean;
11
+ createdAt?: Date;
12
+ updatedAt?: Date;
13
+ }
@@ -0,0 +1,12 @@
1
+ import { Types } from "mongoose";
2
+ import User from "./User";
3
+
4
+ export default interface Keystore {
5
+ _id: Types.ObjectId;
6
+ client: User;
7
+ primaryKey: string;
8
+ secondaryKey: string;
9
+ status?: boolean;
10
+ createdAt?: Date;
11
+ updatedAt?: Date;
12
+ }
@@ -0,0 +1,14 @@
1
+ import { Types } from "mongoose";
2
+
3
+ export enum RoleCode {
4
+ USER = "user",
5
+ ADMIN = "admin"
6
+ }
7
+
8
+ export default interface Role {
9
+ _id: Types.ObjectId;
10
+ code: string;
11
+ status?: boolean;
12
+ createdAt?: Date;
13
+ updatedAt?: Date;
14
+ }
@@ -0,0 +1,16 @@
1
+ import { Types } from "mongoose";
2
+ import Role from "./Role.js";
3
+
4
+ export default interface User {
5
+ _id: Types.ObjectId;
6
+ name?: string;
7
+ email: string;
8
+ password: string;
9
+ roles: Role[];
10
+ verified?: boolean;
11
+ status?: boolean;
12
+ createdAt?: Date;
13
+ updatedAt?: Date;
14
+
15
+ isPasswordCorrect(password: string): Promise<boolean>;
16
+ }
@@ -0,0 +1,22 @@
1
+ import { Request } from 'express';
2
+ import User from '../database/models/User';
3
+ import Keystore from '../database/models/Keystore';
4
+ import ApiKey from './ApiKey';
5
+ declare interface PublicRequest extends Request {
6
+ apiKey: ApiKey;
7
+ }
8
+
9
+ declare interface RoleRequest extends PublicRequest {
10
+ currentRoleCodes: string[];
11
+ }
12
+
13
+ declare interface ProtectedRequest extends RoleRequest {
14
+ user: User;
15
+ accessToken: string;
16
+ keystore: Keystore;
17
+ }
18
+
19
+ declare interface Tokens {
20
+ accessToken: string;
21
+ refreshToken: string;
22
+ }
@@ -0,0 +1,3 @@
1
+ export enum Permission {
2
+ GENERAL = 'GENERAL',
3
+ }