crypt-express-app 1.0.0 → 1.3.1
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.
Potentially problematic release.
This version of crypt-express-app might be problematic. Click here for more details.
- package/README.md +321 -1
- package/{scripts/generate-module.ts → dist/generate-module.js} +24 -81
- package/dist/index.js +118 -17
- package/dist/scripts/generate-app.js +73 -55
- package/dist/scripts/generate-locales.js +22 -26
- package/dist/scripts/generate-middleware.js +69 -67
- package/dist/scripts/generate-module.js +140 -78
- package/dist/scripts/generate-root-files.js +199 -63
- package/dist/scripts/generate-utils.js +811 -46
- package/dist/scripts/setup-prisma.js +14 -13
- package/package.json +10 -5
- package/index.ts +0 -29
- package/scripts/generate-app.ts +0 -104
- package/scripts/generate-locales.ts +0 -36
- package/scripts/generate-middleware.ts +0 -176
- package/scripts/generate-root-files.ts +0 -147
- package/scripts/generate-utils.ts +0 -208
- package/scripts/setup-prisma.ts +0 -26
- package/tsconfig.json +0 -10
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
|
|
4
|
-
const basePath = path.join(
|
|
5
|
-
if (!fs.existsSync(basePath)) {
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
/* ================= redis.ts ================= */
|
|
9
|
-
const redisContent = `
|
|
3
|
+
export function generateUtils(projectDir) {
|
|
4
|
+
const basePath = path.join(projectDir, "src", "utils");
|
|
5
|
+
if (!fs.existsSync(basePath)) {
|
|
6
|
+
fs.mkdirSync(basePath, { recursive: true });
|
|
7
|
+
}
|
|
8
|
+
/* ================= redis.ts ================= */
|
|
9
|
+
const redisContent = `
|
|
10
10
|
import { createClient, RedisClientType } from "redis";
|
|
11
|
-
import {
|
|
11
|
+
import { BOOTSTRAP_CONFIG } from "./consts";
|
|
12
12
|
|
|
13
|
-
let redis: RedisClientType
|
|
14
|
-
|
|
13
|
+
let redis: RedisClientType;
|
|
14
|
+
|
|
15
|
+
redis = createClient({
|
|
16
|
+
url: BOOTSTRAP_CONFIG.REDIS.URL,
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
redis.on("connect", () => {
|
|
@@ -22,6 +24,7 @@ redis.on("error", (err) => {
|
|
|
22
24
|
console.error("❌ Redis Error", err);
|
|
23
25
|
});
|
|
24
26
|
|
|
27
|
+
|
|
25
28
|
export const connectRedis = async () => {
|
|
26
29
|
if (!redis.isOpen) {
|
|
27
30
|
await redis.connect();
|
|
@@ -31,7 +34,12 @@ export const connectRedis = async () => {
|
|
|
31
34
|
export class CacheService {
|
|
32
35
|
async set(key: string, value: any, ttl?: number) {
|
|
33
36
|
const stringValue = JSON.stringify(value);
|
|
34
|
-
|
|
37
|
+
|
|
38
|
+
if (ttl) {
|
|
39
|
+
await redis.set(key, stringValue, { EX: ttl });
|
|
40
|
+
} else {
|
|
41
|
+
await redis.set(key, stringValue);
|
|
42
|
+
}
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
async get<T>(key: string): Promise<T | null> {
|
|
@@ -45,25 +53,31 @@ export class CacheService {
|
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
export const cacheService = new CacheService();
|
|
56
|
+
|
|
48
57
|
export default redis;
|
|
49
58
|
`;
|
|
50
|
-
fs.writeFileSync(path.join(basePath, "redis.ts"), redisContent.trim());
|
|
51
|
-
/* ================= cache.ts ================= */
|
|
52
|
-
const cacheContent = `
|
|
59
|
+
fs.writeFileSync(path.join(basePath, "redis.ts"), redisContent.trim());
|
|
60
|
+
/* ================= cache.ts ================= */
|
|
61
|
+
const cacheContent = `
|
|
62
|
+
// Centralized realm secret cache with TTL support
|
|
63
|
+
|
|
53
64
|
interface CachedSecret {
|
|
54
65
|
value: string;
|
|
55
66
|
expiresAt: number;
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
const realmSecretCache = new Map<string, CachedSecret>();
|
|
59
|
-
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
70
|
+
const DEFAULT_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
60
71
|
|
|
61
|
-
export const getCachedSecret = (realmId: string) => {
|
|
72
|
+
export const getCachedSecret = (realmId: string): string | null => {
|
|
62
73
|
const cached = realmSecretCache.get(realmId);
|
|
63
|
-
if (!cached
|
|
74
|
+
if (!cached) return null;
|
|
75
|
+
|
|
76
|
+
if (cached.expiresAt < Date.now()) {
|
|
64
77
|
realmSecretCache.delete(realmId);
|
|
65
78
|
return null;
|
|
66
79
|
}
|
|
80
|
+
|
|
67
81
|
return cached.value;
|
|
68
82
|
};
|
|
69
83
|
|
|
@@ -74,13 +88,14 @@ export const setCachedSecret = (realmId: string, secret: string, ttlMs = DEFAULT
|
|
|
74
88
|
});
|
|
75
89
|
};
|
|
76
90
|
|
|
91
|
+
// Optional: invalidate manually (on secret rotation)
|
|
77
92
|
export const invalidateSecret = (realmId: string) => {
|
|
78
93
|
realmSecretCache.delete(realmId);
|
|
79
94
|
};
|
|
80
95
|
`;
|
|
81
|
-
fs.writeFileSync(path.join(basePath, "cache.ts"), cacheContent.trim());
|
|
82
|
-
/* ================= redis.dto.ts ================= */
|
|
83
|
-
const redisDtoContent = `
|
|
96
|
+
fs.writeFileSync(path.join(basePath, "cache.ts"), cacheContent.trim());
|
|
97
|
+
/* ================= redis.dto.ts ================= */
|
|
98
|
+
const redisDtoContent = `
|
|
84
99
|
export interface CachedUserProfilePermissionDto {
|
|
85
100
|
userId: string;
|
|
86
101
|
username: string;
|
|
@@ -93,9 +108,9 @@ export interface CachedUserProfilePermissionDto {
|
|
|
93
108
|
permissions: string[];
|
|
94
109
|
}
|
|
95
110
|
`;
|
|
96
|
-
fs.writeFileSync(path.join(basePath, "redis.dto.ts"), redisDtoContent.trim());
|
|
97
|
-
/* ================= logger.ts ================= */
|
|
98
|
-
const loggerContent = `
|
|
111
|
+
fs.writeFileSync(path.join(basePath, "redis.dto.ts"), redisDtoContent.trim());
|
|
112
|
+
/* ================= logger.ts ================= */
|
|
113
|
+
const loggerContent = `
|
|
99
114
|
import winston from "winston";
|
|
100
115
|
|
|
101
116
|
const logger = winston.createLogger({
|
|
@@ -103,43 +118,81 @@ const logger = winston.createLogger({
|
|
|
103
118
|
format: winston.format.combine(
|
|
104
119
|
winston.format.colorize(),
|
|
105
120
|
winston.format.timestamp(),
|
|
106
|
-
winston.format.printf(
|
|
121
|
+
winston.format.printf(
|
|
122
|
+
({ timestamp, level, message }) => \`[\${timestamp}] \${level}: \${message}\`
|
|
123
|
+
)
|
|
107
124
|
),
|
|
108
125
|
transports: [new winston.transports.Console()],
|
|
109
126
|
});
|
|
110
127
|
|
|
111
128
|
export default logger;
|
|
112
129
|
`;
|
|
113
|
-
fs.writeFileSync(path.join(basePath, "logger.ts"), loggerContent.trim());
|
|
114
|
-
/* ================= bootstrap.ts ================= */
|
|
115
|
-
const bootstrapContent = `
|
|
130
|
+
fs.writeFileSync(path.join(basePath, "logger.ts"), loggerContent.trim());
|
|
131
|
+
/* ================= bootstrap.ts ================= */
|
|
132
|
+
const bootstrapContent = `
|
|
116
133
|
import prisma from "../prisma/client";
|
|
134
|
+
import { RESET} from "./consts";
|
|
117
135
|
import logger from "./logger";
|
|
118
136
|
|
|
119
137
|
async function bootstrapSystem() {
|
|
120
|
-
|
|
138
|
+
if (RESET) await wipeAllTables();
|
|
139
|
+
|
|
121
140
|
console.log("🚀 System bootstrap complete");
|
|
122
141
|
}
|
|
123
|
-
|
|
124
142
|
export async function wipeAllTables() {
|
|
125
143
|
try {
|
|
126
|
-
await prisma.$executeRawUnsafe(\`
|
|
144
|
+
await prisma.$executeRawUnsafe(\`
|
|
145
|
+
TRUNCATE TABLE
|
|
146
|
+
"Common",
|
|
147
|
+
RESTART IDENTITY CASCADE;
|
|
148
|
+
\`);
|
|
149
|
+
|
|
127
150
|
logger.info("✅ All tables wiped successfully");
|
|
128
151
|
} catch (error) {
|
|
129
|
-
logger.error(error);
|
|
152
|
+
logger.error("❌ Failed to wipe tables:", error);
|
|
153
|
+
throw error;
|
|
130
154
|
}
|
|
131
155
|
}
|
|
132
156
|
|
|
133
|
-
export default bootstrapSystem
|
|
157
|
+
export default bootstrapSystem
|
|
134
158
|
`;
|
|
135
|
-
fs.writeFileSync(path.join(basePath, "bootstrap.ts"), bootstrapContent.trim());
|
|
136
|
-
/* ================= consts.ts ================= */
|
|
137
|
-
const constsContent = `
|
|
138
|
-
export const
|
|
139
|
-
|
|
159
|
+
fs.writeFileSync(path.join(basePath, "bootstrap.ts"), bootstrapContent.trim());
|
|
160
|
+
/* ================= consts.ts ================= */
|
|
161
|
+
const constsContent = `
|
|
162
|
+
export const CLIENT_NAME = process.env.CLIENT_NAME ?? "IAM_CLIENT"
|
|
163
|
+
export const CLIENT_ID = process.env.BOOTSTRAP_CLIENT_ID ?? "iam-client"
|
|
164
|
+
|
|
165
|
+
export const RESET = process.env.JWT_SECRET || false;
|
|
166
|
+
export const JWT_SECRET = process.env.JWT_SECRET || "supersecret";
|
|
167
|
+
export const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || "1h";
|
|
168
|
+
export const REFRESH_TOKEN_EXPIRES_IN = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
169
|
+
|
|
170
|
+
export const BOOTSTRAP_CONFIG = {
|
|
171
|
+
REDIS: {
|
|
172
|
+
URL: process.env.REDIS_URL ?? "redis://localhost:6374",
|
|
173
|
+
},
|
|
140
174
|
};
|
|
141
175
|
|
|
142
|
-
export enum
|
|
176
|
+
export enum Role {
|
|
177
|
+
ADMIN = "ADMIN",
|
|
178
|
+
MANAGER = "MANAGER",
|
|
179
|
+
VIEWER = "VIEWER",
|
|
180
|
+
AUDITOR = "AUDITOR",
|
|
181
|
+
USER = "USER",
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const ROLE_COMPOSITION = [
|
|
185
|
+
...Object.values(Role),
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
export const ROLES_ARRAY =
|
|
189
|
+
ROLE_COMPOSITION.map((role) => ({
|
|
190
|
+
name: CLIENT_NAME + ":" + role,
|
|
191
|
+
description: \`Role for CLIENT: \${CLIENT_NAME + ":" + role}\`,
|
|
192
|
+
isComposite: false,
|
|
193
|
+
}));
|
|
194
|
+
|
|
195
|
+
export enum TypeAction {
|
|
143
196
|
CREATE = "CREATE",
|
|
144
197
|
READ = "READ",
|
|
145
198
|
READ_ALL = "READ_ALL",
|
|
@@ -151,19 +204,34 @@ export enum Resource {
|
|
|
151
204
|
COMMON = "COMMON",
|
|
152
205
|
}
|
|
153
206
|
|
|
154
|
-
export enum
|
|
207
|
+
export enum TypeResource {
|
|
155
208
|
API_ENDPOINT = "API_ENDPOINT",
|
|
156
209
|
UI_PAGE = "UI_PAGE",
|
|
157
210
|
FILE = "FILE",
|
|
158
211
|
SERVICE = "SERVICE",
|
|
159
212
|
DATASET = "DATASET",
|
|
160
213
|
}
|
|
214
|
+
|
|
215
|
+
export const RESOURCES = Object.values(Resource).map((resource) => ({
|
|
216
|
+
name: resource,
|
|
217
|
+
type: TypeResource.API_ENDPOINT,
|
|
218
|
+
}));
|
|
219
|
+
|
|
220
|
+
export const permissions: string[] = [];
|
|
221
|
+
|
|
222
|
+
for (const resource of RESOURCES) {
|
|
223
|
+
for (const action of Object.values(TypeAction)) {
|
|
224
|
+
permissions.push(\`\${resource.name}:\${action}:\${resource.type}\`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
161
227
|
`;
|
|
162
|
-
fs.writeFileSync(path.join(basePath, "consts.ts"), constsContent.trim());
|
|
163
|
-
/* ================= swagger.ts ================= */
|
|
164
|
-
const swaggerContent = `
|
|
228
|
+
fs.writeFileSync(path.join(basePath, "consts.ts"), constsContent.trim());
|
|
229
|
+
/* ================= swagger.ts ================= */
|
|
230
|
+
const swaggerContent = `
|
|
165
231
|
import swaggerJsdoc from "swagger-jsdoc";
|
|
166
232
|
|
|
233
|
+
const port = process.env.PORT ?? 3000
|
|
234
|
+
|
|
167
235
|
export const swaggerSpec = swaggerJsdoc({
|
|
168
236
|
definition: {
|
|
169
237
|
openapi: "3.0.0",
|
|
@@ -181,11 +249,708 @@ export const swaggerSpec = swaggerJsdoc({
|
|
|
181
249
|
},
|
|
182
250
|
},
|
|
183
251
|
},
|
|
184
|
-
security: [
|
|
185
|
-
|
|
252
|
+
security: [
|
|
253
|
+
{
|
|
254
|
+
bearerAuth: [],
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
servers: [{ url: \`http://localhost:\${port}\` }],
|
|
186
258
|
},
|
|
187
259
|
apis: ["./src/**/*.routes.ts", "./src/**/*.dto.ts"],
|
|
188
260
|
});
|
|
189
261
|
`;
|
|
190
|
-
fs.writeFileSync(path.join(basePath, "swagger.ts"), swaggerContent.trim());
|
|
191
|
-
|
|
262
|
+
fs.writeFileSync(path.join(basePath, "swagger.ts"), swaggerContent.trim());
|
|
263
|
+
/* ================= swagger.ts ================= */
|
|
264
|
+
const scriptDir = path.join(projectDir, "scripts");
|
|
265
|
+
if (!fs.existsSync(scriptDir)) {
|
|
266
|
+
fs.mkdirSync(scriptDir, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
const generateModule = `
|
|
269
|
+
// generate-module.ts
|
|
270
|
+
import * as fs from 'fs';
|
|
271
|
+
import * as path from 'path';
|
|
272
|
+
|
|
273
|
+
// get module name from command line
|
|
274
|
+
const args = process.argv.slice(2);
|
|
275
|
+
|
|
276
|
+
// Check that exactly **one argument** is provided
|
|
277
|
+
if (args.length !== 1) {
|
|
278
|
+
console.error('Invalid module name: provide exactly one module name without spaces.');
|
|
279
|
+
console.error('Example: npm run generate-module clientRole');
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const moduleInput = args[0];
|
|
284
|
+
|
|
285
|
+
// Reject if input contains spaces
|
|
286
|
+
if (/\\s/.test(moduleInput)) {
|
|
287
|
+
console.error('Invalid module name: spaces are not allowed. Use camelCase, kebab-case or snake_case.');
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!moduleInput) {
|
|
292
|
+
console.error('Please provide a module name: npm run generate-module <module-name>');
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Convert any input to camelCase
|
|
297
|
+
const moduleName = moduleInput.includes('-') || moduleInput.includes('_') || moduleInput.includes(' ')
|
|
298
|
+
? moduleInput
|
|
299
|
+
.toLowerCase()
|
|
300
|
+
.replace(/[-_\\s]+(.)/g, (_, c) => c.toUpperCase())
|
|
301
|
+
: moduleInput; // preserve existing camelCase
|
|
302
|
+
|
|
303
|
+
console.log("moduleName: ", moduleName)
|
|
304
|
+
|
|
305
|
+
// Convert any input (camelCase, PascalCase, snake_case, spaces) to kebab-case
|
|
306
|
+
const fileName = moduleName
|
|
307
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2') // add dash before uppercase letters
|
|
308
|
+
.toLowerCase(); // lowercase everything
|
|
309
|
+
|
|
310
|
+
console.log("fileName: ", fileName)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
const basePath = path.join(__dirname, '..', 'src', 'modules', fileName);
|
|
314
|
+
|
|
315
|
+
// Create folder
|
|
316
|
+
if (!fs.existsSync(basePath)) {
|
|
317
|
+
fs.mkdirSync(basePath, { recursive: true });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Capitalize first letter
|
|
321
|
+
const ModuleClassName = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
|
|
322
|
+
|
|
323
|
+
// Service
|
|
324
|
+
const serviceContent = \`import { Create\${ModuleClassName}Dto, Update\${ModuleClassName}Dto, Create\${ModuleClassName}Response, Update\${ModuleClassName}Response, Get\${ModuleClassName}Response, List\${ModuleClassName}Response } from "./\${fileName}.dto";
|
|
325
|
+
import { Prisma } from "@prisma/client";
|
|
326
|
+
import prisma from '../../prisma/client';
|
|
327
|
+
import { PaginationRequestDto } from "../common/common.dto";
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
export class \${ModuleClassName}Service {
|
|
331
|
+
constructor() {}
|
|
332
|
+
|
|
333
|
+
async create(payload: Create\${ModuleClassName}Dto): Promise<Create\${ModuleClassName}Response> {
|
|
334
|
+
try {
|
|
335
|
+
// TODO: create \${ModuleClassName} in database
|
|
336
|
+
return {
|
|
337
|
+
\${moduleName}Id: "generated-\${moduleName}Id",
|
|
338
|
+
...payload,
|
|
339
|
+
createdAt: new Date().toISOString(),
|
|
340
|
+
updatedAt: new Date().toISOString(),
|
|
341
|
+
};
|
|
342
|
+
} catch (error) {
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
async update(\${moduleName}Id: string, payload: Update\${ModuleClassName}Dto): Promise<Update\${ModuleClassName}Response> {
|
|
348
|
+
try {
|
|
349
|
+
// TODO: update \${ModuleClassName} by \${moduleName}Id
|
|
350
|
+
return {
|
|
351
|
+
\${moduleName}Id,
|
|
352
|
+
...payload,
|
|
353
|
+
updatedAt: new Date().toISOString(),
|
|
354
|
+
};
|
|
355
|
+
} catch (error) {
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async getById(\${moduleName}Id: string): Promise<Get\${ModuleClassName}Response> {
|
|
361
|
+
try {
|
|
362
|
+
// TODO: fetch \${ModuleClassName} by \${moduleName}Id
|
|
363
|
+
return {
|
|
364
|
+
\${moduleName}Id,
|
|
365
|
+
name: "Sample \${ModuleClassName}",
|
|
366
|
+
createdAt: new Date().toISOString(),
|
|
367
|
+
updatedAt: new Date().toISOString(),
|
|
368
|
+
};
|
|
369
|
+
} catch (error) {
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async list({
|
|
375
|
+
offset = 0,
|
|
376
|
+
limit = 20,
|
|
377
|
+
search,
|
|
378
|
+
sortBy = "createdAt",
|
|
379
|
+
sortOrder = "desc",
|
|
380
|
+
}: PaginationRequestDto): Promise<{ items: List\${ModuleClassName}Response; total: number }> {
|
|
381
|
+
try {
|
|
382
|
+
// TODO: fetch list of \${ModuleClassName}
|
|
383
|
+
return {
|
|
384
|
+
total: 1,
|
|
385
|
+
items: [
|
|
386
|
+
{
|
|
387
|
+
\${moduleName}Id: "1",
|
|
388
|
+
name: "Sample \${ModuleClassName} 1",
|
|
389
|
+
createdAt: new Date().toISOString(),
|
|
390
|
+
updatedAt: new Date().toISOString(),
|
|
391
|
+
},
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
} catch (error) {
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async delete(\${moduleName}Id: string): Promise<void> {
|
|
400
|
+
try {
|
|
401
|
+
// TODO: delete \${ModuleClassName} by \${moduleName}Id
|
|
402
|
+
return;
|
|
403
|
+
} catch (error) {
|
|
404
|
+
throw error;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export default new \${ModuleClassName}Service()
|
|
410
|
+
\`;
|
|
411
|
+
|
|
412
|
+
fs.writeFileSync(path.join(basePath, \`\${fileName}.service.ts\`), serviceContent);
|
|
413
|
+
|
|
414
|
+
// Controller
|
|
415
|
+
const controllerContent = \`
|
|
416
|
+
import { Request, Response } from 'express';
|
|
417
|
+
import { \${ModuleClassName}Service } from './\${fileName}.service';
|
|
418
|
+
import {
|
|
419
|
+
Create\${ModuleClassName}Dto,
|
|
420
|
+
Update\${ModuleClassName}Dto,
|
|
421
|
+
Create\${ModuleClassName}ResponseDto,
|
|
422
|
+
Update\${ModuleClassName}ResponseDto,
|
|
423
|
+
Get\${ModuleClassName}ResponseDto,
|
|
424
|
+
List\${ModuleClassName}ResponseDto
|
|
425
|
+
} from './\${fileName}.dto';
|
|
426
|
+
import { PaginationRequestDto } from '../common/common.dto';
|
|
427
|
+
|
|
428
|
+
export class \${ModuleClassName}Controller {
|
|
429
|
+
constructor(private \${moduleName}Service: \${ModuleClassName}Service) {}
|
|
430
|
+
|
|
431
|
+
async create(req: Request, res: Response) {
|
|
432
|
+
try {
|
|
433
|
+
const payload: Create\${ModuleClassName}Dto = req.body;
|
|
434
|
+
const data = await this.\${moduleName}Service.create(payload);
|
|
435
|
+
const response: Create\${ModuleClassName}ResponseDto = {
|
|
436
|
+
success: true,
|
|
437
|
+
status: 201,
|
|
438
|
+
message: '\${ModuleClassName} created successfully',
|
|
439
|
+
data,
|
|
440
|
+
};
|
|
441
|
+
res.status(201).json(response);
|
|
442
|
+
} catch (error: any) {
|
|
443
|
+
res.status(500).json({ success: false, status: 500, message: error.message });
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async update(req: Request, res: Response) {
|
|
448
|
+
try {
|
|
449
|
+
const \${moduleName}Id = req.params.\${moduleName}Id as string;
|
|
450
|
+
const payload: Update\${ModuleClassName}Dto = req.body;
|
|
451
|
+
const data = await this.\${moduleName}Service.update(\${moduleName}Id, payload);
|
|
452
|
+
const response: Update\${ModuleClassName}ResponseDto = {
|
|
453
|
+
success: true,
|
|
454
|
+
status: 200,
|
|
455
|
+
message: '\${ModuleClassName} updated successfully',
|
|
456
|
+
data,
|
|
457
|
+
};
|
|
458
|
+
res.json(response);
|
|
459
|
+
} catch (error: any) {
|
|
460
|
+
res.status(500).json({ success: false, status: 500, message: error.message });
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async getById(req: Request, res: Response) {
|
|
465
|
+
try {
|
|
466
|
+
const \${moduleName}Id = req.params.\${moduleName}Id as string;
|
|
467
|
+
const data = await this.\${moduleName}Service.getById(\${moduleName}Id);
|
|
468
|
+
const response: Get\${ModuleClassName}ResponseDto = {
|
|
469
|
+
success: true,
|
|
470
|
+
status: 200,
|
|
471
|
+
message: '\${ModuleClassName} fetched successfully',
|
|
472
|
+
data,
|
|
473
|
+
};
|
|
474
|
+
res.json(response);
|
|
475
|
+
} catch (error: any) {
|
|
476
|
+
res.status(404).json({ success: false, status: 404, message: error.message });
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async list(req: Request, res: Response) {
|
|
481
|
+
try {
|
|
482
|
+
const query = req.query as PaginationRequestDto;
|
|
483
|
+
|
|
484
|
+
const offset = query.offset ? Number(query.offset) : 0;
|
|
485
|
+
const limit = query.limit ? Number(query.limit) : 20;
|
|
486
|
+
const search = query.search;
|
|
487
|
+
const sortBy = query.sortBy || "createdAt";
|
|
488
|
+
const sortOrder = query.sortOrder || "desc";
|
|
489
|
+
const { items, total } =
|
|
490
|
+
await this.\${moduleName}Service.list({
|
|
491
|
+
offset,
|
|
492
|
+
limit,
|
|
493
|
+
search,
|
|
494
|
+
sortBy,
|
|
495
|
+
sortOrder,
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
const response: List\${ModuleClassName}ResponseDto = {
|
|
499
|
+
success: true,
|
|
500
|
+
status: 200,
|
|
501
|
+
message: "\${ModuleClassName} list fetched successfully",
|
|
502
|
+
data: {
|
|
503
|
+
items,
|
|
504
|
+
total,
|
|
505
|
+
offset,
|
|
506
|
+
limit,
|
|
507
|
+
},
|
|
508
|
+
};
|
|
509
|
+
res.json(response);
|
|
510
|
+
} catch (error: any) {
|
|
511
|
+
res.status(500).json({ success: false, status: 500, message: error.message });
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async delete(req: Request, res: Response) {
|
|
516
|
+
try {
|
|
517
|
+
const \${moduleName}Id = req.params.\${moduleName}Id as string;
|
|
518
|
+
await this.\${moduleName}Service.delete(\${moduleName}Id);
|
|
519
|
+
res.json({
|
|
520
|
+
success: true,
|
|
521
|
+
status: 200,
|
|
522
|
+
message: '\${ModuleClassName} deleted successfully',
|
|
523
|
+
});
|
|
524
|
+
} catch (error: any) {
|
|
525
|
+
res.status(500).json({ success: false, status: 500, message: error.message });
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
\`;
|
|
530
|
+
|
|
531
|
+
fs.writeFileSync(path.join(basePath, \`\${fileName}.controller.ts\`), controllerContent);
|
|
532
|
+
|
|
533
|
+
// Routes
|
|
534
|
+
const routesContent = \`
|
|
535
|
+
import express, { Router } from 'express';
|
|
536
|
+
import { \${ModuleClassName}Controller } from './\${fileName}.controller';
|
|
537
|
+
import { \${moduleName}Middleware } from './\${fileName}.middlewares';
|
|
538
|
+
import { authMiddleware } from '../../middlewares/auth.middleware';
|
|
539
|
+
import \${moduleName}Service from './\${fileName}.service';
|
|
540
|
+
import { TypeAction, Resource, TypeResource } from '../../utils/consts';
|
|
541
|
+
import { authorizationMiddleware } from '../../middlewares/authorization.middleware';
|
|
542
|
+
|
|
543
|
+
const router: Router = express.Router();
|
|
544
|
+
const controller = new \${ModuleClassName}Controller(\${moduleName}Service);
|
|
545
|
+
router.use(authMiddleware);
|
|
546
|
+
const guard = (actions: TypeAction[]) => authorizationMiddleware({ resource: Resource.COMMON, actions, resourceType: TypeResource.API_ENDPOINT });
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @openapi
|
|
550
|
+
* tags:
|
|
551
|
+
* - name: \${ModuleClassName}
|
|
552
|
+
* description: \${ModuleClassName} management and operations
|
|
553
|
+
*/
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* @openapi
|
|
557
|
+
* /api/\${moduleName}:
|
|
558
|
+
* post:
|
|
559
|
+
* tags: [\${ModuleClassName}]
|
|
560
|
+
* summary: Create a new \${ModuleClassName}
|
|
561
|
+
* requestBody:
|
|
562
|
+
* required: true
|
|
563
|
+
* content:
|
|
564
|
+
* application/json:
|
|
565
|
+
* schema:
|
|
566
|
+
* $ref: '#/components/schemas/Create\${ModuleClassName}Dto'
|
|
567
|
+
* responses:
|
|
568
|
+
* 201:
|
|
569
|
+
* description: \${ModuleClassName} created successfully
|
|
570
|
+
* content:
|
|
571
|
+
* application/json:
|
|
572
|
+
* schema:
|
|
573
|
+
* $ref: '#/components/schemas/Create\${ModuleClassName}ResponseDto'
|
|
574
|
+
*/
|
|
575
|
+
router.post('/', \${moduleName}Middleware, guard([TypeAction.CREATE]), controller.create.bind(controller));
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* @openapi
|
|
579
|
+
* /api/\${moduleName}/{\${moduleName}Id}:
|
|
580
|
+
* get:
|
|
581
|
+
* tags: [\${ModuleClassName}]
|
|
582
|
+
* summary: Get a \${ModuleClassName} by ID
|
|
583
|
+
* parameters:
|
|
584
|
+
* - name: \${moduleName}Id
|
|
585
|
+
* in: path
|
|
586
|
+
* required: true
|
|
587
|
+
* schema:
|
|
588
|
+
* type: string
|
|
589
|
+
* responses:
|
|
590
|
+
* 200:
|
|
591
|
+
* description: \${ModuleClassName} fetched successfully
|
|
592
|
+
* content:
|
|
593
|
+
* application/json:
|
|
594
|
+
* schema:
|
|
595
|
+
* $ref: '#/components/schemas/Get\${ModuleClassName}ResponseDto'
|
|
596
|
+
*/
|
|
597
|
+
router.get('/:\${moduleName}Id', \${moduleName}Middleware, guard([TypeAction.READ]), controller.getById.bind(controller));
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* @openapi
|
|
601
|
+
* /api/\${moduleName}/{\${moduleName}Id}:
|
|
602
|
+
* put:
|
|
603
|
+
* tags: [\${ModuleClassName}]
|
|
604
|
+
* summary: Update a \${ModuleClassName} by ID
|
|
605
|
+
* parameters:
|
|
606
|
+
* - name: \${moduleName}Id
|
|
607
|
+
* in: path
|
|
608
|
+
* required: true
|
|
609
|
+
* schema:
|
|
610
|
+
* type: string
|
|
611
|
+
* requestBody:
|
|
612
|
+
* required: true
|
|
613
|
+
* content:
|
|
614
|
+
* application/json:
|
|
615
|
+
* schema:
|
|
616
|
+
* $ref: '#/components/schemas/Update\${ModuleClassName}Dto'
|
|
617
|
+
* responses:
|
|
618
|
+
* 200:
|
|
619
|
+
* description: \${ModuleClassName} updated successfully
|
|
620
|
+
* content:
|
|
621
|
+
* application/json:
|
|
622
|
+
* schema:
|
|
623
|
+
* $ref: '#/components/schemas/Update\${ModuleClassName}ResponseDto'
|
|
624
|
+
*/
|
|
625
|
+
router.put('/:\${moduleName}Id', \${moduleName}Middleware, guard([TypeAction.UPDATE]), controller.update.bind(controller));
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* @openapi
|
|
629
|
+
* /api/\${moduleName}/{\${moduleName}Id}:
|
|
630
|
+
* delete:
|
|
631
|
+
* tags: [\${ModuleClassName}]
|
|
632
|
+
* summary: Delete a \${ModuleClassName} by ID
|
|
633
|
+
* parameters:
|
|
634
|
+
* - name: \${moduleName}Id
|
|
635
|
+
* in: path
|
|
636
|
+
* required: true
|
|
637
|
+
* schema:
|
|
638
|
+
* type: string
|
|
639
|
+
* responses:
|
|
640
|
+
* 200:
|
|
641
|
+
* description: \${ModuleClassName} deleted successfully
|
|
642
|
+
* content:
|
|
643
|
+
* application/json:
|
|
644
|
+
* schema:
|
|
645
|
+
* type: object
|
|
646
|
+
* properties:
|
|
647
|
+
* success:
|
|
648
|
+
* type: boolean
|
|
649
|
+
* status:
|
|
650
|
+
* type: integer
|
|
651
|
+
* message:
|
|
652
|
+
* type: string
|
|
653
|
+
*/
|
|
654
|
+
router.delete('/:\${moduleName}Id', \${moduleName}Middleware, guard([TypeAction.DELETE]), controller.delete.bind(controller));
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* @openapi
|
|
658
|
+
* /api/\${moduleName}:
|
|
659
|
+
* get:
|
|
660
|
+
* tags: [\${ModuleClassName}]
|
|
661
|
+
* summary: List all \${ModuleClassName}s with pagination
|
|
662
|
+
* parameters:
|
|
663
|
+
* - in: query
|
|
664
|
+
* name: offset
|
|
665
|
+
* schema:
|
|
666
|
+
* type: integer
|
|
667
|
+
* description: Offset for pagination
|
|
668
|
+
* - in: query
|
|
669
|
+
* name: limit
|
|
670
|
+
* schema:
|
|
671
|
+
* type: integer
|
|
672
|
+
* description: Limit for pagination
|
|
673
|
+
* - in: query
|
|
674
|
+
* name: search
|
|
675
|
+
* schema:
|
|
676
|
+
* type: string
|
|
677
|
+
* description: Search keyword
|
|
678
|
+
* - in: query
|
|
679
|
+
* name: sortBy
|
|
680
|
+
* schema:
|
|
681
|
+
* type: string
|
|
682
|
+
* description: Field to sort by
|
|
683
|
+
* - in: query
|
|
684
|
+
* name: sortOrder
|
|
685
|
+
* schema:
|
|
686
|
+
* type: string
|
|
687
|
+
* enum: [asc, desc]
|
|
688
|
+
* description: Sort order
|
|
689
|
+
* responses:
|
|
690
|
+
* 200:
|
|
691
|
+
* description: List of \${ModuleClassName}s
|
|
692
|
+
* content:
|
|
693
|
+
* application/json:
|
|
694
|
+
* schema:
|
|
695
|
+
* $ref: '#/components/schemas/List\${ModuleClassName}ResponseDto'
|
|
696
|
+
*/
|
|
697
|
+
router.get('/', \${moduleName}Middleware, guard([TypeAction.READ_ALL]), controller.list.bind(controller));
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* ======================================================
|
|
701
|
+
* Optional: Health Check
|
|
702
|
+
* ======================================================
|
|
703
|
+
*/
|
|
704
|
+
router.get('/health/check', (_req, res) => {
|
|
705
|
+
res.json({
|
|
706
|
+
success: true,
|
|
707
|
+
status: 200,
|
|
708
|
+
message: "\${ModuleClassName} module is healthy",
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
export default router;
|
|
713
|
+
\`;
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
fs.writeFileSync(path.join(basePath, \`\${fileName}.routes.ts\`), routesContent);
|
|
717
|
+
const dtoContent = \`import { ApiResponse, PaginatedData } from "../common/common.dto";
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Main \${ModuleClassName} entity
|
|
721
|
+
*
|
|
722
|
+
* @openapi
|
|
723
|
+
* components:
|
|
724
|
+
* schemas:
|
|
725
|
+
* \${ModuleClassName}:
|
|
726
|
+
* type: object
|
|
727
|
+
* required:
|
|
728
|
+
* - name
|
|
729
|
+
* properties:
|
|
730
|
+
* \${moduleName}Id:
|
|
731
|
+
* type: string
|
|
732
|
+
* example: "c3f2a9b4-8d21-4f3b-a91c-1a2b3c4d5e6f"
|
|
733
|
+
* description: Unique identifier of the \${ModuleClassName}
|
|
734
|
+
* name:
|
|
735
|
+
* type: string
|
|
736
|
+
* example: Sample \${ModuleClassName}
|
|
737
|
+
* description: Name of the \${ModuleClassName}
|
|
738
|
+
* description:
|
|
739
|
+
* type: string
|
|
740
|
+
* example: Optional description
|
|
741
|
+
* nullable: true
|
|
742
|
+
* description: Description of the \${ModuleClassName}
|
|
743
|
+
* createdAt:
|
|
744
|
+
* type: string
|
|
745
|
+
* format: date-time
|
|
746
|
+
* example: "2025-01-01T10:00:00.000Z"
|
|
747
|
+
* description: Creation timestamp
|
|
748
|
+
* updatedAt:
|
|
749
|
+
* type: string
|
|
750
|
+
* format: date-time
|
|
751
|
+
* example: "2025-01-02T12:00:00.000Z"
|
|
752
|
+
* description: Last update timestamp
|
|
753
|
+
*/
|
|
754
|
+
export interface \${ModuleClassName} {
|
|
755
|
+
\${moduleName}Id: string;
|
|
756
|
+
name: string;
|
|
757
|
+
description?: string;
|
|
758
|
+
createdAt: string;
|
|
759
|
+
updatedAt: string;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* @openapi
|
|
764
|
+
* components:
|
|
765
|
+
* schemas:
|
|
766
|
+
* Create\${ModuleClassName}Dto:
|
|
767
|
+
* type: object
|
|
768
|
+
* required:
|
|
769
|
+
* - name
|
|
770
|
+
* properties:
|
|
771
|
+
* name:
|
|
772
|
+
* type: string
|
|
773
|
+
* example: Sample \${ModuleClassName}
|
|
774
|
+
* description: Name of the \${ModuleClassName}
|
|
775
|
+
* description:
|
|
776
|
+
* type: string
|
|
777
|
+
* example: Sample description
|
|
778
|
+
*/
|
|
779
|
+
export interface Create\${ModuleClassName}Dto {
|
|
780
|
+
name: string;
|
|
781
|
+
description?: string;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* @openapi
|
|
786
|
+
* components:
|
|
787
|
+
* schemas:
|
|
788
|
+
* Update\${ModuleClassName}Dto:
|
|
789
|
+
* type: object
|
|
790
|
+
* properties:
|
|
791
|
+
* name:
|
|
792
|
+
* type: string
|
|
793
|
+
* example: Updated \${ModuleClassName} Name
|
|
794
|
+
* description:
|
|
795
|
+
* type: string
|
|
796
|
+
* example: Updated description
|
|
797
|
+
*/
|
|
798
|
+
export interface Update\${ModuleClassName}Dto {
|
|
799
|
+
name?: string;
|
|
800
|
+
description?: string;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* ======================================================
|
|
805
|
+
* Service return types (data only, controller wraps response)
|
|
806
|
+
* ======================================================
|
|
807
|
+
*/
|
|
808
|
+
|
|
809
|
+
// data returned from service
|
|
810
|
+
export type Create\${ModuleClassName}Response = Partial<\${ModuleClassName}>;
|
|
811
|
+
export type Update\${ModuleClassName}Response = Partial<\${ModuleClassName}>;
|
|
812
|
+
export type Get\${ModuleClassName}Response = Partial<\${ModuleClassName}>;
|
|
813
|
+
export type List\${ModuleClassName}Response = Partial<\${ModuleClassName}>[];
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* ======================================================
|
|
817
|
+
* API Response DTOs (Swagger documented)
|
|
818
|
+
* ======================================================
|
|
819
|
+
*/
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* @openapi
|
|
823
|
+
* components:
|
|
824
|
+
* schemas:
|
|
825
|
+
* Create\${ModuleClassName}ResponseDto:
|
|
826
|
+
* allOf:
|
|
827
|
+
* - $ref: '#/components/schemas/ApiResponse'
|
|
828
|
+
* - type: object
|
|
829
|
+
* properties:
|
|
830
|
+
* data:
|
|
831
|
+
* $ref: '#/components/schemas/\${ModuleClassName}'
|
|
832
|
+
*/
|
|
833
|
+
export interface Create\${ModuleClassName}ResponseDto
|
|
834
|
+
extends ApiResponse<Partial<\${ModuleClassName}>> {}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* @openapi
|
|
838
|
+
* components:
|
|
839
|
+
* schemas:
|
|
840
|
+
* Update\${ModuleClassName}ResponseDto:
|
|
841
|
+
* allOf:
|
|
842
|
+
* - $ref: '#/components/schemas/ApiResponse'
|
|
843
|
+
* - type: object
|
|
844
|
+
* properties:
|
|
845
|
+
* data:
|
|
846
|
+
* $ref: '#/components/schemas/\${ModuleClassName}'
|
|
847
|
+
*/
|
|
848
|
+
export interface Update\${ModuleClassName}ResponseDto
|
|
849
|
+
extends ApiResponse<Partial<\${ModuleClassName}>> {}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* @openapi
|
|
853
|
+
* components:
|
|
854
|
+
* schemas:
|
|
855
|
+
* Get\${ModuleClassName}ResponseDto:
|
|
856
|
+
* allOf:
|
|
857
|
+
* - $ref: '#/components/schemas/ApiResponse'
|
|
858
|
+
* - type: object
|
|
859
|
+
* properties:
|
|
860
|
+
* data:
|
|
861
|
+
* $ref: '#/components/schemas/\${ModuleClassName}'
|
|
862
|
+
*/
|
|
863
|
+
export interface Get\${ModuleClassName}ResponseDto
|
|
864
|
+
extends ApiResponse<Partial<\${ModuleClassName}>> {}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* @openapi
|
|
868
|
+
* components:
|
|
869
|
+
* schemas:
|
|
870
|
+
* List\${ModuleClassName}ResponseDto:
|
|
871
|
+
* allOf:
|
|
872
|
+
* - $ref: '#/components/schemas/ApiResponse'
|
|
873
|
+
* - type: object
|
|
874
|
+
* properties:
|
|
875
|
+
* data:
|
|
876
|
+
* type: object
|
|
877
|
+
* properties:
|
|
878
|
+
* items:
|
|
879
|
+
* type: array
|
|
880
|
+
* items:
|
|
881
|
+
* $ref: '#/components/schemas/\${ModuleClassName}'
|
|
882
|
+
* total:
|
|
883
|
+
* type: integer
|
|
884
|
+
* offset:
|
|
885
|
+
* type: integer
|
|
886
|
+
* limit:
|
|
887
|
+
* type: integer
|
|
888
|
+
*/
|
|
889
|
+
export interface List\${ModuleClassName}ResponseDto
|
|
890
|
+
extends ApiResponse<PaginatedData<Partial<\${ModuleClassName}>>> {}
|
|
891
|
+
\`;
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
fs.writeFileSync(path.join(basePath, \`\${fileName}.dto.ts\`), dtoContent);
|
|
895
|
+
|
|
896
|
+
// Middleware
|
|
897
|
+
const middlewareContent = \`
|
|
898
|
+
import { Request, Response, NextFunction } from "express";
|
|
899
|
+
import { cacheService } from "../../utils/redis";
|
|
900
|
+
import { CachedUserProfilePermissionDto } from "../../utils/redis.dto";
|
|
901
|
+
|
|
902
|
+
export async function \${moduleName}Middleware(req: Request, res: Response, next: NextFunction) {
|
|
903
|
+
try {
|
|
904
|
+
const { userId } = req.user!
|
|
905
|
+
const profile = await cacheService.get<CachedUserProfilePermissionDto>(user:\\\${userId}:permissions);
|
|
906
|
+
if(!profile) throw new Error("No permission found")
|
|
907
|
+
const userPermissions = profile;
|
|
908
|
+
|
|
909
|
+
const method = req.method;
|
|
910
|
+
const url = req.originalUrl;
|
|
911
|
+
const path = req.path;
|
|
912
|
+
const \${moduleName}Id = req?.params?.\${moduleName}Id
|
|
913
|
+
|
|
914
|
+
console.log("---- REALM MIDDLEWARE ----");
|
|
915
|
+
console.log("Method:", method);
|
|
916
|
+
console.log("URL:", url);
|
|
917
|
+
console.log("Path:", path);
|
|
918
|
+
|
|
919
|
+
// Example condition checking
|
|
920
|
+
if (method === "POST" && path === "/") {
|
|
921
|
+
console.log("👉 Creating new realm");
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
if (method === "GET" && path === "/") {
|
|
925
|
+
console.log("👉 Listing realms");
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
if (method === "GET" && \${moduleName}Id) {
|
|
929
|
+
console.log("👉 Getting realm by ID:", \${moduleName}Id);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
if (method === "PUT") {
|
|
933
|
+
console.log("👉 Updating realm");
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (method === "DELETE") {
|
|
937
|
+
console.log("👉 Deleting realm");
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
next();
|
|
941
|
+
} catch (error) {
|
|
942
|
+
return res.status(500).json({
|
|
943
|
+
message: "Authorization error",
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
\`;
|
|
948
|
+
|
|
949
|
+
fs.writeFileSync(path.join(basePath, \`\${fileName}.middlewares.ts\`), middlewareContent);
|
|
950
|
+
|
|
951
|
+
console.log(\`Module '\${moduleName}' generated successfully at \${basePath}\`);
|
|
952
|
+
|
|
953
|
+
`;
|
|
954
|
+
fs.writeFileSync(path.join(scriptDir, "generate-module.ts"), generateModule.trim());
|
|
955
|
+
console.log("✅ Utils files generated successfully inside src/utils");
|
|
956
|
+
}
|