create-forgeapi 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/README.md +79 -0
- package/dist/bin/index.d.ts +2 -0
- package/dist/bin/index.js +286 -0
- package/package.json +37 -0
- package/template/.env.example +7 -0
- package/template/nodemon.json +7 -0
- package/template/package.json +21 -0
- package/template/src/App.ts +1 -0
- package/template/src/api/controllers/UserController.ts +54 -0
- package/template/src/api/middlewares/AuthMiddleware.ts +24 -0
- package/template/src/base/BaseRepository.ts +112 -0
- package/template/src/base/BaseResponse.ts +45 -0
- package/template/src/base/BaseResponseError.ts +12 -0
- package/template/src/base/BaseSchema.ts +82 -0
- package/template/src/config/DateTimeConfig.ts +4 -0
- package/template/src/config/GlobalHandlerError.ts +81 -0
- package/template/src/config/LoggerConfig.ts +157 -0
- package/template/src/config/LookupConfig.ts +68 -0
- package/template/src/config/MetaDataConfig.ts +25 -0
- package/template/src/config/RouteConfig.ts +98 -0
- package/template/src/config/SwaggerConfig.ts +147 -0
- package/template/src/config/envConfig.ts +5 -0
- package/template/src/core/Server.ts +75 -0
- package/template/src/core/exceptions/BadRequestException.ts +7 -0
- package/template/src/core/exceptions/ForbiddenException.ts +7 -0
- package/template/src/core/exceptions/NotFoundException.ts +7 -0
- package/template/src/core/exceptions/UnauthorizedException.ts +7 -0
- package/template/src/core/repositories/UserRepository.ts +53 -0
- package/template/src/database/DatabaseConnection.ts +11 -0
- package/template/src/database/builder/CustomBuilder.ts +177 -0
- package/template/src/database/builder/CustomFilter.ts +12 -0
- package/template/src/database/builder/MultipleSearchCriteria.ts +25 -0
- package/template/src/database/builder/SearchCriteria.ts +79 -0
- package/template/src/database/entity/ProfileModel.ts +54 -0
- package/template/src/database/entity/UserModel.ts +46 -0
- package/template/src/shared/decorators/ApiDecorator.ts +88 -0
- package/template/src/shared/decorators/LookupDecorator.ts +51 -0
- package/template/src/shared/decorators/MethodeDecorator.ts +38 -0
- package/template/src/shared/helpers/VirtualHelper.ts +53 -0
- package/template/src/shared/interfaces/BaseInterface.ts +14 -0
- package/template/src/shared/interfaces/DatabaseInterface.ts +41 -0
- package/template/src/shared/interfaces/HttpInterface.ts +37 -0
- package/template/src/shared/interfaces/LoggerOptionsInterface.ts +16 -0
- package/template/src/shared/interfaces/MiddlewareInterface.ts +14 -0
- package/template/src/shared/interfaces/RouteMetadataInterface.ts +10 -0
- package/template/src/shared/interfaces/SoftDeleteInterface.ts +8 -0
- package/template/src/shared/interfaces/SwaggerMetadataInterface.ts +12 -0
- package/template/src/shared/interfaces/UserInterface.ts +37 -0
- package/template/src/shared/interfaces/user/UserCreateInterface.ts +4 -0
- package/template/src/shared/models/enum/MiddlewareEnum.ts +19 -0
- package/template/src/shared/models/request/UserCreateRequest.ts +12 -0
- package/template/src/shared/models/response/ApiResponse.ts +27 -0
- package/template/src/shared/types/express.d.ts +14 -0
- package/template/src/shared/types/mongoose.d.ts +7 -0
- package/template/src/shared/utils/ColorUtil.ts +17 -0
- package/template/src/shared/utils/DatabaseUtil.ts +3 -0
- package/template/src/shared/utils/DecoratorUtil.ts +4 -0
- package/template/src/shared/utils/FolderUtil.ts +15 -0
- package/template/src/shared/utils/JwtUtil.ts +21 -0
- package/template/src/shared/utils/SwaggerUtil.ts +107 -0
- package/template/src/shared/utils/TimeUtil.ts +74 -0
- package/template/tsconfig.dev.json +9 -0
- package/template/tsconfig.json +33 -0
- package/template/tsconfig.prod.json +10 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {ZodType} from "zod";
|
|
2
|
+
|
|
3
|
+
type OpenApiSchema = Record<string, any>;
|
|
4
|
+
|
|
5
|
+
function zodToOpenApi(schema: ZodType): OpenApiSchema {
|
|
6
|
+
const def = (schema as any)._def;
|
|
7
|
+
const typeName: string = def?.type ?? '';
|
|
8
|
+
|
|
9
|
+
switch (typeName) {
|
|
10
|
+
case 'optional':
|
|
11
|
+
case 'nullable':
|
|
12
|
+
case 'default':
|
|
13
|
+
return zodToOpenApi(def.innerType);
|
|
14
|
+
|
|
15
|
+
case 'string':
|
|
16
|
+
return { type: 'string' };
|
|
17
|
+
|
|
18
|
+
case 'number':
|
|
19
|
+
case 'int':
|
|
20
|
+
case 'float':
|
|
21
|
+
return { type: 'number' };
|
|
22
|
+
|
|
23
|
+
case 'boolean':
|
|
24
|
+
return { type: 'boolean' };
|
|
25
|
+
|
|
26
|
+
case 'array': {
|
|
27
|
+
return {
|
|
28
|
+
type: 'array',
|
|
29
|
+
items: zodToOpenApi(def.element)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
case 'literal': {
|
|
34
|
+
const val = def.values?.[0];
|
|
35
|
+
const litType = typeof val === 'boolean' ? 'boolean' : typeof val === 'number' ? 'number' : 'string';
|
|
36
|
+
return { type: litType, example: val };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
case 'enum': {
|
|
40
|
+
const values = Object.values(def.entries ?? {});
|
|
41
|
+
const enumType = typeof values[0] === 'number' ? 'number' : 'string';
|
|
42
|
+
return { type: enumType, enum: values };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
case 'record':
|
|
46
|
+
return { type: 'object', additionalProperties: zodToOpenApi(def.valueType ?? def.element) };
|
|
47
|
+
|
|
48
|
+
case 'unknown':
|
|
49
|
+
case 'any':
|
|
50
|
+
return {};
|
|
51
|
+
|
|
52
|
+
case 'object': {
|
|
53
|
+
const shape: Record<string, ZodType> = def.shape ?? {};
|
|
54
|
+
const properties: OpenApiSchema = {};
|
|
55
|
+
const required: string[] = [];
|
|
56
|
+
|
|
57
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
58
|
+
properties[key] = zodToOpenApi(fieldSchema as ZodType);
|
|
59
|
+
const fieldDef = (fieldSchema as any)._def;
|
|
60
|
+
const isOptional = fieldDef?.type === 'optional' || fieldDef?.type === 'nullable';
|
|
61
|
+
if (!isOptional) {
|
|
62
|
+
required.push(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties,
|
|
69
|
+
...(required.length > 0 ? { required } : {})
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
default:
|
|
74
|
+
return { type: 'string' };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default class SwaggerUtil {
|
|
79
|
+
static generateSchema(type: ZodType): OpenApiSchema {
|
|
80
|
+
if (!type) return {};
|
|
81
|
+
return zodToOpenApi(type);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static generateParameters(type: ZodType, location: 'path' | 'query'): OpenApiSchema[] {
|
|
85
|
+
if (!type) return [];
|
|
86
|
+
|
|
87
|
+
const def = (type as any)._def;
|
|
88
|
+
if (def?.type !== 'object') return [];
|
|
89
|
+
|
|
90
|
+
const shape: Record<string, ZodType> = def.shape ?? {};
|
|
91
|
+
const parameters: OpenApiSchema[] = [];
|
|
92
|
+
|
|
93
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
94
|
+
const fieldDef = (fieldSchema as any)._def;
|
|
95
|
+
const isOptional = fieldDef?.type === 'optional' || fieldDef?.type === 'nullable';
|
|
96
|
+
|
|
97
|
+
parameters.push({
|
|
98
|
+
name: key,
|
|
99
|
+
in: location,
|
|
100
|
+
required: location === 'path' ? true : !isOptional,
|
|
101
|
+
schema: zodToOpenApi(fieldSchema as ZodType)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return parameters;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {DAY_VALUES, MONTH_VALUES} from "@config/DateTimeConfig";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export default class TimeUtil {
|
|
5
|
+
static getTimestamp(): string {
|
|
6
|
+
const now = new Date();
|
|
7
|
+
return now.toISOString();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static getTimeString() {
|
|
11
|
+
return new Date().toLocaleString()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static formatDuration(ms: number): string {
|
|
15
|
+
if (ms < 1000) return `${ms.toFixed(0)}ms`;
|
|
16
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Private helper methods to avoid duplication
|
|
20
|
+
private static getDateComponents(date: Date) {
|
|
21
|
+
return {
|
|
22
|
+
day: date.getDate().toString().padStart(2, '0'),
|
|
23
|
+
month: MONTH_VALUES[date.getMonth()],
|
|
24
|
+
year: date.getFullYear(),
|
|
25
|
+
dayName: DAY_VALUES[date.getDay()]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private static getTimeComponents(date: Date) {
|
|
30
|
+
return {
|
|
31
|
+
hours: date.getHours().toString().padStart(2, '0'),
|
|
32
|
+
minutes: date.getMinutes().toString().padStart(2, '0'),
|
|
33
|
+
seconds: date.getSeconds().toString().padStart(2, '0')
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static getDateTimeString(date: Date): string {
|
|
38
|
+
const year = date.getFullYear();
|
|
39
|
+
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
40
|
+
const day = date.getDate().toString().padStart(2, '0');
|
|
41
|
+
const {hours, minutes, seconds} = this.getTimeComponents(date);
|
|
42
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static getReadableDate(date: Date): string {
|
|
46
|
+
const {day, month, year} = this.getDateComponents(date);
|
|
47
|
+
return `${day} ${month} ${year}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static getReadableDateTimeNoSecond(date: Date): string {
|
|
51
|
+
const {day, month, year} = this.getDateComponents(date);
|
|
52
|
+
return `${day} ${month} ${year} ${this.getReadableTime(date)}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static getReadableDateTime(date: Date): string {
|
|
56
|
+
const {day, month, year} = this.getDateComponents(date);
|
|
57
|
+
return `${day} ${month} ${year} ${this.getReadableTimeSecond(date)}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static getReadableDayDateTime(date: Date): string {
|
|
61
|
+
const {day, month, year, dayName} = this.getDateComponents(date);
|
|
62
|
+
return `${dayName}, ${day} ${month} ${year} ${this.getReadableTimeSecond(date)}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static getReadableTime(date: Date): string {
|
|
66
|
+
const {hours, minutes} = this.getTimeComponents(date);
|
|
67
|
+
return `${hours}:${minutes}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static getReadableTimeSecond(date: Date): string {
|
|
71
|
+
const {hours, minutes, seconds} = this.getTimeComponents(date);
|
|
72
|
+
return `${hours}:${minutes}:${seconds}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2021",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2021"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"experimentalDecorators": true,
|
|
10
|
+
"emitDecoratorMetadata": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"declarationMap": true,
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"paths": {
|
|
20
|
+
// "@/*": ["src/*"],
|
|
21
|
+
"@api/*": ["src/api/*"],
|
|
22
|
+
"@core/*": ["src/core/*"],
|
|
23
|
+
"@database/*": ["src/database/*"],
|
|
24
|
+
"@shared/*": ["src/shared/*"],
|
|
25
|
+
"@config/*": ["src/config/*"],
|
|
26
|
+
"@base/*": ["src/base/*"],
|
|
27
|
+
},
|
|
28
|
+
"typeRoots": ["./node_modules/@types", "./src/types", "./src/shared/types"]
|
|
29
|
+
},
|
|
30
|
+
"include": ["src/**/*"],
|
|
31
|
+
"files": ["src/shared/types/mongoose.d.ts", "src/shared/types/express.d.ts"],
|
|
32
|
+
"exclude": ["node_modules", "dist"]
|
|
33
|
+
}
|