create-stackflow 1.0.4 → 1.0.7

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.
@@ -1,8 +1,12 @@
1
1
  import path from "node:path";
2
2
  import fs from "fs-extra";
3
3
  import ora from "ora";
4
- import { execa } from "execa";
5
4
  import { ext, writeTemplate } from "../utils/template.js";
5
+ import {
6
+ chatBackendFiles,
7
+ chatServerSocketBlock,
8
+ patchMainRouteForChat,
9
+ } from "./chat.js";
6
10
 
7
11
  export async function createBackend(context) {
8
12
  const spinner = ora("Generating backend API").start();
@@ -15,26 +19,16 @@ export async function createBackend(context) {
15
19
  throw error;
16
20
  }
17
21
 
18
- if (!context.skipInstall) {
19
- const install = ora("Installing backend dependencies").start();
20
- try {
21
- await execa("npm", ["install"], { cwd: context.backendDir, stdio: "ignore" });
22
- install.succeed("Installing backend dependencies");
23
- } catch (error) {
24
- install.fail("Installing backend dependencies");
25
- throw error;
26
- }
27
- }
28
22
  }
29
23
 
30
24
  async function writeBackendFiles(context) {
31
25
  const backendContext = { ...context, language: context.backendLanguage || context.language };
32
26
  const e = ext(backendContext);
33
27
  const isTs = backendContext.language === "typescript";
28
+ const esm = isTs || context.backendModule !== "cjs";
34
29
  const clientUrl = context.frontend === "next" ? "http://localhost:3000" : "http://localhost:5173";
35
30
  const deps = {
36
31
  bcryptjs: "latest",
37
- "cookie-parser": context.cookieParser === false ? undefined : "latest",
38
32
  cors: context.cors === false ? undefined : "latest",
39
33
  dotenv: "latest",
40
34
  express: "latest",
@@ -54,7 +48,6 @@ async function writeBackendFiles(context) {
54
48
  const devDeps = isTs
55
49
  ? {
56
50
  "@types/bcryptjs": "latest",
57
- "@types/cookie-parser": "latest",
58
51
  "@types/cors": "latest",
59
52
  "@types/express": "latest",
60
53
  "@types/jsonwebtoken": "latest",
@@ -70,7 +63,7 @@ async function writeBackendFiles(context) {
70
63
  await writeTemplate(path.join(context.backendDir, "package.json"), JSON.stringify({
71
64
  name: path.basename(context.backendDir),
72
65
  version: "1.0.0",
73
- type: "module",
66
+ ...(esm ? { type: "module" } : {}),
74
67
  private: true,
75
68
  scripts: {
76
69
  dev: isTs ? "tsx watch src/server.ts" : "nodemon src/server.js",
@@ -85,8 +78,8 @@ async function writeBackendFiles(context) {
85
78
  await writeTemplate(path.join(context.backendDir, "tsconfig.json"), `{
86
79
  "compilerOptions": {
87
80
  "target": "ES2022",
88
- "module": "NodeNext",
89
- "moduleResolution": "NodeNext",
81
+ "module": "${context.backendModule === "cjs" ? "CommonJS" : "NodeNext"}",
82
+ "moduleResolution": "${context.backendModule === "cjs" ? "Node" : "NodeNext"}",
90
83
  "strict": false,
91
84
  "noImplicitAny": false,
92
85
  "noCheck": true,
@@ -106,7 +99,6 @@ CLIENT_URL={{clientUrl}}
106
99
  MONGODB_URI=mongodb://127.0.0.1:27017/{{databaseName}}
107
100
  JWT_SECRET=change_this_super_secret_value
108
101
  JWT_EXPIRES_IN=7d
109
- COOKIE_NAME=stackflow_token
110
102
  {{cloudinaryEnv}}
111
103
  `, { ...context, clientUrl, cloudinaryEnv: context.cloudinary ? "CLOUDINARY_CLOUD_NAME=\nCLOUDINARY_API_KEY=\nCLOUDINARY_API_SECRET=" : "" });
112
104
 
@@ -116,15 +108,19 @@ COOKIE_NAME=stackflow_token
116
108
  "src/middleware",
117
109
  "src/models",
118
110
  "src/routes",
119
- "src/services",
120
111
  "src/utils",
121
- "src/validations"
122
112
  ];
123
113
  if (context.multer) dirs.push("uploads");
124
114
  await Promise.all(dirs.map((dir) => fs.ensureDir(path.join(context.backendDir, dir))));
125
115
  if (context.multer) await fs.outputFile(path.join(context.backendDir, "uploads", ".gitkeep"), "");
126
116
 
127
- const files = backendTemplates({ ...context, language: backendContext.language, clientUrl }, e);
117
+ const files = backendTemplates({ ...context, language: backendContext.language, clientUrl, esm }, e);
118
+
119
+ if (!context.cloudinary) delete files[`src/config/cloudinary.${e}`];
120
+ if (!context.multer) delete files[`src/middleware/uploadMiddleware.${e}`];
121
+ if (!context.winston) delete files[`src/utils/logger.${e}`];
122
+ if (!context.swagger) delete files[`src/config/swagger.${e}`];
123
+
128
124
  await Promise.all(Object.entries(files).map(([file, content]) =>
129
125
  writeTemplate(path.join(context.backendDir, file), content, context)
130
126
  ));
@@ -136,61 +132,65 @@ function compact(object) {
136
132
 
137
133
  function backendTemplates(context, e) {
138
134
  const isTs = context.language === "typescript";
135
+ const esm = context.esm !== false;
136
+ const rel = (p) => (esm ? `${p}.js` : p);
137
+ const im = (binding, from, relative = false) => {
138
+ const src = relative ? rel(from) : from;
139
+ return esm
140
+ ? `import ${binding} from "${src}";`
141
+ : `const ${binding} = require("${src}");`;
142
+ };
143
+ const imDefault = (binding, from, relative = false) => im(binding, from, relative);
144
+ const imn = (names, from, relative = false) => {
145
+ const src = relative ? rel(from) : from;
146
+ return esm
147
+ ? `import { ${names} } from "${src}";`
148
+ : `const { ${names} } = require("${src}");`;
149
+ };
139
150
  const type = (name) => isTs ? `: ${name}` : "";
140
151
  const reqRes = isTs ? "import type { Request, Response, NextFunction } from \"express\";\n" : "";
141
152
  const imports = {
142
- logger: context.winston ? "import { logger } from \"./utils/logger.js\";" : "",
143
- morgan: context.morgan ? "import morgan from \"morgan\";" : "",
144
- swagger: context.swagger ? "import { setupSwagger } from \"./config/swagger.js\";" : "",
145
- socket: context.socketio ? "import { Server } from \"socket.io\";" : ""
153
+ logger: context.winston ? (esm ? imn("logger", "./utils/logger", true) : imn("logger", "./utils/logger", true)) : "",
154
+ morgan: context.morgan ? im("morgan", "morgan") : "",
155
+ swagger: context.swagger ? (esm ? imn("setupSwagger", "./config/swagger", true) : imn("setupSwagger", "./config/swagger", true)) : "",
156
+ socket: context.socketio ? imn("Server", "socket.io") : "",
146
157
  };
147
158
 
148
- return {
149
- [`src/server.${e}`]: `import http from "node:http";
150
- import app from "./app.js";
151
- import { connectDB } from "./config/db.js";
159
+ const templates = {
160
+ [`src/server.${e}`]: `${im("http", "node:http")}
161
+ ${imDefault("app", "./app", true)}
162
+ ${imn("connectDB", "./config/db", true)}
152
163
  ${imports.socket}
153
164
  ${imports.logger}
154
165
 
155
166
  const PORT = Number(process.env.PORT) || 5000;
156
167
 
157
- async function bootstrap() {
168
+ async function startServer() {
158
169
  await connectDB();
159
170
  const server = http.createServer(app);
160
- ${context.socketio ? `
161
- const io = new Server(server, {
162
- cors: {
163
- origin: process.env.CLIENT_URL || "${context.clientUrl}",
164
- credentials: true
165
- }
166
- });
167
-
168
- io.on("connection", (socket) => {
169
- socket.emit("connected", { message: "Socket.IO connected" });
170
- });
171
- ` : ""}
171
+ ${chatServerSocketBlock(context, context.clientUrl, { imn })}
172
172
  server.listen(PORT, () => {
173
173
  ${context.winston ? "logger.info(`API running on http://localhost:${PORT}`);" : "console.log(`API running on http://localhost:${PORT}`);"}
174
174
  });
175
175
  }
176
176
 
177
- bootstrap().catch((error) => {
177
+ startServer().catch((error) => {
178
178
  ${context.winston ? "logger.error(error);" : "console.error(error);"}
179
179
  process.exit(1);
180
180
  });
181
181
  `,
182
182
  [`src/app.${e}`]: `import "dotenv/config";
183
183
  import express from "express";
184
- ${context.cookieParser === false ? "" : "import cookieParser from \"cookie-parser\";"}
185
184
  ${context.cors === false ? "" : "import cors from \"cors\";"}
186
185
  ${context.helmet === false ? "" : "import helmet from \"helmet\";"}
187
186
  ${context.rateLimit === false ? "" : "import rateLimit from \"express-rate-limit\";"}
188
187
  ${context.hpp ? "import hpp from \"hpp\";" : ""}
189
188
  ${imports.morgan}
190
189
  ${imports.swagger}
191
- import apiRoutes from "./routes/index.routes.js";
192
- import { errorHandler } from "./middleware/error.middleware.js";
193
- import { notFound } from "./middleware/not-found.middleware.js";
190
+ ${context.multer ? "import { uploadsStatic } from \"./middleware/uploadMiddleware.js\";" : ""}
191
+ import apiRoutes from "./routes/mainRoute.js";
192
+ import { errorHandler } from "./middleware/errorMiddleware.js";
193
+ import { notFound } from "./middleware/notFoundMiddleware.js";
194
194
 
195
195
  const app = express();
196
196
 
@@ -201,17 +201,12 @@ ${context.cors === false ? "" : `app.use(cors({
201
201
  credentials: true
202
202
  }));`}
203
203
  ${context.rateLimit === false ? "" : "app.use(rateLimit({ windowMs: 15 * 60 * 1000, limit: 300 }));"}
204
- app.use("/uploads", express.static("uploads"));
204
+ ${context.multer ? 'app.use("/uploads", uploadsStatic);' : ""}
205
205
  app.use(express.json({ limit: "1mb" }));
206
206
  app.use(express.urlencoded({ extended: true }));
207
- ${context.cookieParser === false ? "" : "app.use(cookieParser());"}
208
207
  ${context.morgan ? "app.use(morgan(\"dev\"));" : ""}
209
208
  ${context.swagger ? "setupSwagger(app);" : ""}
210
209
 
211
- app.get("/api/health", (_req, res) => {
212
- res.json({ status: "ok", service: "stackflow-api" });
213
- });
214
-
215
210
  app.use("/api", apiRoutes);
216
211
  app.use(notFound);
217
212
  app.use(errorHandler);
@@ -228,7 +223,7 @@ export async function connectDB() {
228
223
  ${context.winston ? "logger.info(\"MongoDB connected\");" : "console.log(\"MongoDB connected\");"}
229
224
  }
230
225
  `,
231
- [`src/models/user.model.${e}`]: `import mongoose from "mongoose";
226
+ [`src/models/userModel.${e}`]: `import mongoose from "mongoose";
232
227
  import bcrypt from "bcryptjs";
233
228
 
234
229
  const userSchema = new mongoose.Schema({
@@ -248,9 +243,9 @@ userSchema.methods.comparePassword = function(candidatePassword) {
248
243
 
249
244
  export const User = mongoose.model("User", userSchema);
250
245
  `,
251
- [`src/models/task.model.${e}`]: `import mongoose from "mongoose";
246
+ [`src/models/todoModel.${e}`]: `import mongoose from "mongoose";
252
247
 
253
- const taskSchema = new mongoose.Schema({
248
+ const todoSchema = new mongoose.Schema({
254
249
  title: { type: String, required: true, trim: true },
255
250
  description: { type: String, default: "" },
256
251
  imageUrl: { type: String, default: "" },
@@ -258,7 +253,7 @@ const taskSchema = new mongoose.Schema({
258
253
  owner: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }
259
254
  }, { timestamps: true });
260
255
 
261
- export const Task = mongoose.model("Task", taskSchema);
256
+ export const Todo = mongoose.model("Todo", todoSchema);
262
257
  `,
263
258
  [`src/utils/jwt.${e}`]: `import jwt from "jsonwebtoken";
264
259
 
@@ -267,41 +262,34 @@ export function signToken(userId) {
267
262
  expiresIn: process.env.JWT_EXPIRES_IN || "7d"
268
263
  });
269
264
  }
270
-
271
- export function setAuthCookie(res, token) {
272
- res.cookie(process.env.COOKIE_NAME || "stackflow_token", token, {
273
- httpOnly: true,
274
- sameSite: "lax",
275
- secure: process.env.NODE_ENV === "production",
276
- maxAge: 7 * 24 * 60 * 60 * 1000
277
- });
278
- }
279
265
  `,
280
- [`src/middleware/auth.middleware.${e}`]: `${reqRes}import jwt from "jsonwebtoken";
281
- import { User } from "../models/user.model.js";
266
+ [`src/middleware/authMiddleware.${e}`]: `${reqRes}import jwt from "jsonwebtoken";
267
+ import { User } from "../models/userModel.js";
282
268
 
283
269
  export async function protect(req${type("Request & { user?: unknown }")}, res${type("Response")}, next${type("NextFunction")}) {
284
270
  try {
285
- const cookieToken = req.cookies?.[process.env.COOKIE_NAME || "stackflow_token"];
286
- const headerToken = req.headers.authorization?.startsWith("Bearer ")
271
+ const token = req.headers.authorization?.startsWith("Bearer ")
287
272
  ? req.headers.authorization.split(" ")[1]
288
273
  : undefined;
289
- const token = cookieToken || headerToken;
290
- if (!token) return res.status(401).json({ message: "Authentication required" });
274
+ if (!token) {
275
+ return res.status(401).json({ success: false, message: "Authentication required" });
276
+ }
291
277
 
292
278
  const decoded = jwt.verify(token, process.env.JWT_SECRET || "dev_secret");
293
279
  const userId = typeof decoded === "object" && "userId" in decoded ? decoded.userId : null;
294
280
  const user = await User.findById(userId).select("-password");
295
- if (!user) return res.status(401).json({ message: "Invalid authentication" });
281
+ if (!user) {
282
+ return res.status(401).json({ success: false, message: "Invalid authentication" });
283
+ }
296
284
 
297
285
  req.user = user;
298
286
  next();
299
287
  } catch {
300
- res.status(401).json({ message: "Invalid or expired token" });
288
+ res.status(401).json({ success: false, message: "Invalid or expired token" });
301
289
  }
302
290
  }
303
291
  `,
304
- [`src/middleware/error.middleware.${e}`]: `${reqRes}export function errorHandler(error${type("Error & { statusCode?: number }")}, _req${type("Request")}, res${type("Response")}, _next${type("NextFunction")}) {
292
+ [`src/middleware/errorMiddleware.${e}`]: `${reqRes}export function errorHandler(error${type("Error & { statusCode?: number }")}, _req${type("Request")}, res${type("Response")}, _next${type("NextFunction")}) {
305
293
  const status = error.statusCode || 500;
306
294
  res.status(status).json({
307
295
  message: error.message || "Server error",
@@ -309,169 +297,234 @@ export async function protect(req${type("Request & { user?: unknown }")}, res${t
309
297
  });
310
298
  }
311
299
  `,
312
- [`src/middleware/not-found.middleware.${e}`]: `${reqRes}export function notFound(req${type("Request")}, res${type("Response")}) {
300
+ [`src/middleware/notFoundMiddleware.${e}`]: `${reqRes}export function notFound(req${type("Request")}, res${type("Response")}) {
313
301
  res.status(404).json({ message: \`Route not found: \${req.originalUrl}\` });
314
302
  }
315
303
  `,
316
- [`src/controllers/auth.controller.${e}`]: `import { User } from "../models/user.model.js";
317
- import { signToken, setAuthCookie } from "../utils/jwt.js";
304
+ [`src/controllers/authController.${e}`]: `import { User } from "../models/userModel.js";
305
+ import { signToken } from "../utils/jwt.js";
318
306
 
319
307
  function publicUser(user) {
320
308
  return { id: user._id, name: user.name, email: user.email };
321
309
  }
322
310
 
323
- export async function register(req, res, next) {
324
- try {
325
- const { name, email, password } = req.body;
326
- const existing = await User.findOne({ email });
327
- if (existing) return res.status(409).json({ message: "Email already registered" });
328
- const user = await User.create({ name, email, password });
329
- const token = signToken(user._id);
330
- setAuthCookie(res, token);
331
- res.status(201).json({ user: publicUser(user), token });
332
- } catch (error) {
333
- next(error);
334
- }
335
- }
311
+ const authController = {
312
+ // Register
313
+ register: async (req, res) => {
314
+ try {
315
+ const { name, email, password } = req.body;
316
+ const existing = await User.findOne({ email });
317
+ if (existing) {
318
+ return res.status(409).json({ success: false, message: "Email already registered" });
319
+ }
320
+ const user = await User.create({ name, email, password });
321
+ const token = signToken(user._id);
322
+ res.status(201).json({
323
+ success: true,
324
+ message: "Account created successfully",
325
+ data: { user: publicUser(user), token }
326
+ });
327
+ } catch (error) {
328
+ res.status(500).json({ success: false, message: error.message });
329
+ }
330
+ },
336
331
 
337
- export async function login(req, res, next) {
338
- try {
339
- const { email, password } = req.body;
340
- const user = await User.findOne({ email });
341
- if (!user || !(await user.comparePassword(password))) {
342
- return res.status(401).json({ message: "Invalid email or password" });
332
+ // Login
333
+ login: async (req, res) => {
334
+ try {
335
+ const { email, password } = req.body;
336
+ const user = await User.findOne({ email });
337
+ if (!user || !(await user.comparePassword(password))) {
338
+ return res.status(401).json({ success: false, message: "Invalid email or password" });
339
+ }
340
+ const token = signToken(user._id);
341
+ res.status(200).json({
342
+ success: true,
343
+ message: "Logged in successfully",
344
+ data: { user: publicUser(user), token }
345
+ });
346
+ } catch (error) {
347
+ res.status(500).json({ success: false, message: error.message });
343
348
  }
344
- const token = signToken(user._id);
345
- setAuthCookie(res, token);
346
- res.json({ user: publicUser(user), token });
347
- } catch (error) {
348
- next(error);
349
- }
350
- }
349
+ },
351
350
 
352
- export async function me(req, res) {
353
- res.json({ user: publicUser(req.user) });
354
- }
351
+ // Current user
352
+ me: async (req, res) => {
353
+ try {
354
+ res.status(200).json({
355
+ success: true,
356
+ message: "Profile fetched successfully",
357
+ data: { user: publicUser(req.user) }
358
+ });
359
+ } catch (error) {
360
+ res.status(500).json({ success: false, message: error.message });
361
+ }
362
+ },
355
363
 
356
- export async function logout(_req, res) {
357
- res.clearCookie(process.env.COOKIE_NAME || "stackflow_token");
358
- res.json({ message: "Logged out" });
359
- }
364
+ // Logout (client clears token)
365
+ logout: async (_req, res) => {
366
+ res.status(200).json({
367
+ success: true,
368
+ message: "Logged out successfully"
369
+ });
370
+ }
371
+ };
372
+
373
+ export default authController;
360
374
  `,
361
- [`src/controllers/task.controller.${e}`]: `import { Task } from "../models/task.model.js";
375
+ [`src/controllers/todoController.${e}`]: `import { Todo } from "../models/todoModel.js";
362
376
 
363
- export async function listTasks(req, res, next) {
364
- try {
365
- const tasks = await Task.find({ owner: req.user._id }).sort({ createdAt: -1 });
366
- res.json({ tasks });
367
- } catch (error) {
368
- next(error);
369
- }
370
- }
377
+ const todoController = {
378
+ // Get All Todos
379
+ getTodos: async (req, res) => {
380
+ try {
381
+ const todos = await Todo.find({ owner: req.user._id }).sort({ createdAt: -1 });
382
+ res.status(200).json({
383
+ success: true,
384
+ message: "Todos fetched successfully",
385
+ data: todos
386
+ });
387
+ } catch (error) {
388
+ res.status(500).json({
389
+ success: false,
390
+ message: error.message
391
+ });
392
+ }
393
+ },
371
394
 
372
- export async function createTask(req, res, next) {
373
- try {
374
- const imageUrl = req.file ? \`/uploads/\${req.file.filename}\` : "";
375
- const task = await Task.create({ ...req.body, imageUrl, owner: req.user._id });
376
- res.status(201).json({ task });
377
- } catch (error) {
378
- next(error);
379
- }
380
- }
395
+ // Create Todo
396
+ createTodo: async (req, res) => {
397
+ try {
398
+ const imageUrl = req.file ? \`/uploads/\${req.file.filename}\` : "";
399
+ const newTodo = await Todo.create({ ...req.body, imageUrl, owner: req.user._id });
400
+ res.status(201).json({
401
+ success: true,
402
+ message: "Todo created successfully",
403
+ data: newTodo
404
+ });
405
+ } catch (error) {
406
+ res.status(500).json({
407
+ success: false,
408
+ message: error.message
409
+ });
410
+ }
411
+ },
381
412
 
382
- export async function updateTask(req, res, next) {
383
- try {
384
- const updates = { ...req.body };
385
- if (req.file) updates.imageUrl = \`/uploads/\${req.file.filename}\`;
386
- const task = await Task.findOneAndUpdate(
387
- { _id: req.params.id, owner: req.user._id },
388
- updates,
389
- { new: true, runValidators: true }
390
- );
391
- if (!task) return res.status(404).json({ message: "Task not found" });
392
- res.json({ task });
393
- } catch (error) {
394
- next(error);
395
- }
396
- }
413
+ // Update Todo
414
+ updateTodo: async (req, res) => {
415
+ try {
416
+ const { id } = req.params;
417
+ const updates = { ...req.body };
418
+ if (req.file) updates.imageUrl = \`/uploads/\${req.file.filename}\`;
419
+ const todo = await Todo.findOneAndUpdate(
420
+ { _id: id, owner: req.user._id },
421
+ updates,
422
+ { new: true, runValidators: true }
423
+ );
424
+ if (!todo) return res.status(404).json({ success: false, message: "Todo not found" });
425
+ res.status(200).json({
426
+ success: true,
427
+ message: \`Todo \${id} updated successfully\`,
428
+ data: todo
429
+ });
430
+ } catch (error) {
431
+ res.status(500).json({
432
+ success: false,
433
+ message: error.message
434
+ });
435
+ }
436
+ },
397
437
 
398
- export async function deleteTask(req, res, next) {
399
- try {
400
- const task = await Task.findOneAndDelete({ _id: req.params.id, owner: req.user._id });
401
- if (!task) return res.status(404).json({ message: "Task not found" });
402
- res.json({ message: "Task deleted" });
403
- } catch (error) {
404
- next(error);
438
+ // Delete Todo
439
+ deleteTodo: async (req, res) => {
440
+ try {
441
+ const { id } = req.params;
442
+ const todo = await Todo.findOneAndDelete({ _id: id, owner: req.user._id });
443
+ if (!todo) return res.status(404).json({ success: false, message: "Todo not found" });
444
+ res.status(200).json({
445
+ success: true,
446
+ message: \`Todo \${id} deleted successfully\`
447
+ });
448
+ } catch (error) {
449
+ res.status(500).json({
450
+ success: false,
451
+ message: error.message
452
+ });
453
+ }
405
454
  }
406
- }
455
+ };
456
+
457
+ export default todoController;
407
458
  `,
408
- [`src/routes/auth.routes.${e}`]: `import { Router } from "express";
409
- import { login, logout, me, register } from "../controllers/auth.controller.js";
410
- import { protect } from "../middleware/auth.middleware.js";
459
+ [`src/routes/authRoute.${e}`]: `import { Router } from "express";
460
+ import authController from "../controllers/authController.js";
461
+ import { protect } from "../middleware/authMiddleware.js";
411
462
 
412
463
  const router = Router();
413
464
 
414
- router.post("/register", register);
415
- router.post("/login", login);
416
- router.get("/me", protect, me);
417
- router.post("/logout", logout);
465
+ router.post("/register", authController.register);
466
+ router.post("/login", authController.login);
467
+ router.get("/me", protect, authController.me);
468
+ router.post("/logout", protect, authController.logout);
418
469
 
419
470
  export default router;
420
471
  `,
421
- [`src/routes/index.routes.${e}`]: `import { Router } from "express";
422
- import authRoutes from "./auth.routes.js";
423
- import taskRoutes from "./task.routes.js";
472
+ [`src/routes/mainRoute.${e}`]: `import { Router } from "express";
473
+ import authRoutes from "./authRoute.js";
474
+ import todoRoutes from "./todoRoute.js";
424
475
 
425
476
  const router = Router();
426
477
 
427
478
  router.use("/auth", authRoutes);
428
- router.use("/tasks", taskRoutes);
479
+ router.use("/todos", todoRoutes);
429
480
 
430
481
  export default router;
431
482
  `,
432
- [`src/routes/task.routes.${e}`]: `import { Router } from "express";
433
- import { createTask, deleteTask, listTasks, updateTask } from "../controllers/task.controller.js";
434
- import { protect } from "../middleware/auth.middleware.js";
435
- ${context.multer ? "import { upload } from \"../services/upload.service.js\";" : ""}
483
+ [`src/routes/todoRoute.${e}`]: `import { Router } from "express";
484
+ import todoController from "../controllers/todoController.js";
485
+ import { protect } from "../middleware/authMiddleware.js";
486
+ ${context.multer ? "import { upload } from \"../middleware/uploadMiddleware.js\";" : ""}
436
487
 
437
488
  const router = Router();
438
489
 
439
490
  router.use(protect);
440
- router.get("/", listTasks);
441
- router.post("/", ${context.multer ? "upload.single(\"image\"), " : ""}createTask);
442
- router.patch("/:id", ${context.multer ? "upload.single(\"image\"), " : ""}updateTask);
443
- router.delete("/:id", deleteTask);
491
+
492
+ router.get("/", todoController.getTodos);
493
+ router.post("/", ${context.multer ? "upload.single(\"image\"), " : ""}todoController.createTodo);
494
+ router.put("/:id", ${context.multer ? "upload.single(\"image\"), " : ""}todoController.updateTodo);
495
+ router.delete("/:id", todoController.deleteTodo);
444
496
 
445
497
  export default router;
446
498
  `,
447
- [`src/services/upload.service.${e}`]: context.multer ? `import multer from "multer";
448
-
449
- const storage = multer.diskStorage({
499
+ [`src/middleware/uploadMiddleware.${e}`]: context.multer
500
+ ? `${im("multer", "multer")}
501
+ ${im("express", "express")}
502
+ ${esm ? "" : "const { diskStorage } = multer;\n"}
503
+ const storage = ${esm ? "multer.diskStorage" : "diskStorage"}({
450
504
  destination: "uploads/",
451
505
  filename: (_req, file, callback) => {
452
506
  callback(null, \`\${Date.now()}-\${file.originalname}\`);
453
507
  }
454
508
  });
455
509
 
456
- export const upload = multer({ storage });
457
- ` : `export {};
458
- `,
459
- [`src/validations/auth.validation.${e}`]: `export const authValidation = {
460
- register: ["name", "email", "password"],
461
- login: ["email", "password"]
462
- };
463
- `,
464
- [`src/utils/logger.${e}`]: context.winston ? `import winston from "winston";
510
+ ${esm ? "export const upload = multer({ storage });" : "const upload = multer({ storage });\n"}
511
+ ${esm ? "export const uploadsStatic = express.static(\"uploads\");" : "const uploadsStatic = express.static(\"uploads\");\n"}
512
+ ${esm ? "" : "module.exports = { upload, uploadsStatic };"}
513
+ `
514
+ : undefined,
515
+ [`src/utils/logger.${e}`]: context.winston
516
+ ? `${im("winston", "winston")}
465
517
 
466
- export const logger = winston.createLogger({
518
+ const logger = winston.createLogger({
467
519
  level: "info",
468
520
  format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
469
521
  transports: [new winston.transports.Console()]
470
522
  });
471
- ` : `export const logger = console;
472
- `,
473
- [`src/config/swagger.${e}`]: context.swagger ? `import swaggerJSDoc from "swagger-jsdoc";
474
- import swaggerUi from "swagger-ui-express";
523
+ ${esm ? "export { logger };" : "module.exports = { logger };"}
524
+ `
525
+ : undefined,
526
+ [`src/config/swagger.${e}`]: context.swagger ? `${im("swaggerJSDoc", "swagger-jsdoc")}
527
+ ${im("swaggerUi", "swagger-ui-express")}
475
528
 
476
529
  export function setupSwagger(app) {
477
530
  const spec = swaggerJSDoc({
@@ -484,9 +537,11 @@ export function setupSwagger(app) {
484
537
 
485
538
  app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(spec));
486
539
  }
487
- ` : `export function setupSwagger() {}
488
- `,
489
- [`src/config/cloudinary.${e}`]: context.cloudinary ? `import { v2 as cloudinary } from "cloudinary";
540
+ ${esm ? "" : "\nmodule.exports = { setupSwagger };"}
541
+ `
542
+ : undefined,
543
+ [`src/config/cloudinary.${e}`]: context.cloudinary
544
+ ? `${esm ? 'import { v2 as cloudinary } from "cloudinary";' : 'const { v2: cloudinary } = require("cloudinary");'}
490
545
 
491
546
  cloudinary.config({
492
547
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
@@ -494,8 +549,25 @@ cloudinary.config({
494
549
  api_secret: process.env.CLOUDINARY_API_SECRET
495
550
  });
496
551
 
497
- export { cloudinary };
498
- ` : `export {};
552
+ ${esm ? "export { cloudinary };" : "module.exports = { cloudinary };"}
499
553
  `
554
+ : undefined,
500
555
  };
556
+
557
+ const merged = {
558
+ ...templates,
559
+ ...chatBackendFiles(context, e, { im, imn, esm }),
560
+ };
561
+
562
+ if (merged[`src/routes/mainRoute.${e}`]) {
563
+ merged[`src/routes/mainRoute.${e}`] = patchMainRouteForChat(
564
+ merged[`src/routes/mainRoute.${e}`],
565
+ context,
566
+ e,
567
+ );
568
+ }
569
+
570
+ return Object.fromEntries(
571
+ Object.entries(merged).filter(([, value]) => value !== undefined),
572
+ );
501
573
  }