create-charcole 2.0.4 → 2.1.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 (75) hide show
  1. package/CHANGELOG.md +200 -14
  2. package/README.md +137 -332
  3. package/bin/index.js +236 -55
  4. package/bin/lib/pkgManager.js +8 -25
  5. package/bin/lib/templateHandler.js +5 -42
  6. package/package.json +2 -2
  7. package/plans/V2_1_PLAN.md +20 -0
  8. package/template/js/.env.example +8 -0
  9. package/template/js/basePackage.json +11 -13
  10. package/template/js/src/app.js +4 -1
  11. package/template/js/src/modules/auth/auth.constants.js +3 -0
  12. package/template/js/src/modules/auth/auth.controller.js +29 -0
  13. package/template/js/src/modules/auth/auth.middlewares.js +19 -0
  14. package/template/js/src/modules/auth/auth.routes.js +9 -0
  15. package/template/js/src/modules/auth/auth.schemas.js +60 -0
  16. package/template/js/src/modules/auth/auth.service.js +67 -0
  17. package/template/js/src/modules/auth/package.json +6 -0
  18. package/template/js/src/repositories/user.repo.js +19 -0
  19. package/template/js/src/routes/index.js +25 -0
  20. package/template/js/src/routes/protected.js +13 -0
  21. package/template/ts/.env.example +8 -0
  22. package/template/ts/basePackage.json +19 -15
  23. package/template/ts/build.js +46 -0
  24. package/template/ts/src/app.ts +5 -4
  25. package/template/ts/src/middlewares/errorHandler.ts +15 -23
  26. package/template/ts/src/middlewares/requestLogger.ts +1 -1
  27. package/template/ts/src/middlewares/validateRequest.ts +1 -1
  28. package/template/ts/src/modules/auth/auth.constants.ts +6 -0
  29. package/template/ts/src/modules/auth/auth.controller.ts +32 -0
  30. package/template/ts/src/modules/auth/auth.middlewares.ts +46 -0
  31. package/template/ts/src/modules/auth/auth.routes.ts +9 -0
  32. package/template/ts/src/modules/auth/auth.schemas.ts +73 -0
  33. package/template/ts/src/modules/auth/auth.service.ts +106 -0
  34. package/template/ts/src/modules/auth/package.json +10 -0
  35. package/template/ts/src/modules/health/controller.ts +3 -3
  36. package/template/ts/src/repositories/user.repo.ts +33 -0
  37. package/template/ts/src/routes/index.ts +24 -0
  38. package/template/ts/src/routes/protected.ts +13 -0
  39. package/template/ts/src/server.ts +0 -1
  40. package/template/ts/src/utils/logger.ts +1 -1
  41. package/template/ts/tsconfig.json +14 -7
  42. package/template/js/ARCHITECTURE_DIAGRAMS.md +0 -283
  43. package/template/js/CHECKLIST.md +0 -279
  44. package/template/js/COMPLETE.md +0 -405
  45. package/template/js/ERROR_HANDLING.md +0 -393
  46. package/template/js/IMPLEMENTATION.md +0 -368
  47. package/template/js/IMPLEMENTATION_COMPLETE.md +0 -363
  48. package/template/js/INDEX.md +0 -290
  49. package/template/js/QUICK_REFERENCE.md +0 -270
  50. package/template/js/package.json +0 -28
  51. package/template/js/src/routes.js +0 -17
  52. package/template/js/test-api.js +0 -100
  53. package/template/ts/ARCHITECTURE_DIAGRAMS.md +0 -283
  54. package/template/ts/CHECKLIST.md +0 -279
  55. package/template/ts/COMPLETE.md +0 -405
  56. package/template/ts/ERROR_HANDLING.md +0 -393
  57. package/template/ts/IMPLEMENTATION.md +0 -368
  58. package/template/ts/IMPLEMENTATION_COMPLETE.md +0 -363
  59. package/template/ts/INDEX.md +0 -290
  60. package/template/ts/QUICK_REFERENCE.md +0 -270
  61. package/template/ts/package.json +0 -32
  62. package/template/ts/src/app.js +0 -75
  63. package/template/ts/src/config/constants.js +0 -20
  64. package/template/ts/src/config/env.js +0 -26
  65. package/template/ts/src/middlewares/errorHandler.js +0 -180
  66. package/template/ts/src/middlewares/requestLogger.js +0 -33
  67. package/template/ts/src/middlewares/validateRequest.js +0 -42
  68. package/template/ts/src/modules/health/controller.js +0 -50
  69. package/template/ts/src/routes.js +0 -17
  70. package/template/ts/src/routes.ts +0 -16
  71. package/template/ts/src/server.js +0 -38
  72. package/template/ts/src/utils/AppError.js +0 -182
  73. package/template/ts/src/utils/logger.js +0 -73
  74. package/template/ts/src/utils/response.js +0 -51
  75. package/template/ts/test-api.js +0 -100
@@ -0,0 +1,10 @@
1
+ {
2
+ "dependencies": {
3
+ "bcryptjs": "^3.0.3",
4
+ "jsonwebtoken": "^9.0.3"
5
+ },
6
+ "devDependencies": {
7
+ "@types/bcryptjs": "^2.4.6",
8
+ "@types/jsonwebtoken": "^9.0.10"
9
+ }
10
+ }
@@ -1,8 +1,8 @@
1
1
  import { Request, Response } from "express";
2
2
  import { z } from "zod";
3
- import { sendSuccess } from "../../utils/response.js";
4
- import { asyncHandler } from "../../middlewares/errorHandler.js";
5
- import { validateRequest } from "../../middlewares/validateRequest.js";
3
+ import { sendSuccess } from "../../utils/response.ts";
4
+ import { asyncHandler } from "../../middlewares/errorHandler.ts";
5
+ import { validateRequest } from "../../middlewares/validateRequest.ts";
6
6
 
7
7
  const healthCheckSchema = z.object({
8
8
  query: z.object({}),
@@ -0,0 +1,33 @@
1
+ import { randomUUID } from "crypto";
2
+ import type { User } from "../modules/auth/auth.schemas.ts";
3
+
4
+ const users: User[] = [];
5
+
6
+ type CreateUserData = {
7
+ email: string;
8
+ name: string;
9
+ passwordHash: string;
10
+ };
11
+
12
+ export const userRepo = {
13
+ async findByEmail(email: string): Promise<User | undefined> {
14
+ return users.find((u) => u.email === email);
15
+ },
16
+
17
+ async create(data: CreateUserData): Promise<User> {
18
+ const user: User = {
19
+ id: randomUUID(),
20
+ email: data.email,
21
+ name: data.name,
22
+ passwordHash: data.passwordHash,
23
+ role: "user",
24
+ provider: "credentials",
25
+ isEmailVerified: false,
26
+ createdAt: new Date(),
27
+ updatedAt: new Date(),
28
+ };
29
+
30
+ users.push(user);
31
+ return user;
32
+ },
33
+ };
@@ -0,0 +1,24 @@
1
+ import { Router } from "express";
2
+ import {
3
+ getHealth,
4
+ createItem,
5
+ createItemSchema,
6
+ } from "../modules/health/controller.ts";
7
+ import { validateRequest } from "../middlewares/validateRequest.ts";
8
+ import protectedRoutes from "./protected.ts";
9
+ import authRoutes from "../modules/auth/auth.routes.ts";
10
+ const router = Router();
11
+
12
+ // Health check
13
+ router.get("/health", getHealth);
14
+
15
+ // Example: Create item with validation
16
+ router.post("/items", validateRequest(createItemSchema), createItem);
17
+
18
+ // 🔐 Auth routes
19
+ router.use("/auth", authRoutes);
20
+
21
+ // 🔐 Protected routes (REQUIRED BEARER TOKEN FOR THEM)
22
+ router.use("/protected", protectedRoutes);
23
+
24
+ export default router;
@@ -0,0 +1,13 @@
1
+ import { Router } from "express";
2
+ import { requireAuth } from "../modules/auth/auth.middlewares.ts";
3
+
4
+ const router = Router();
5
+
6
+ router.get("/me", requireAuth, (req, res) => {
7
+ res.json({
8
+ message: "You are authenticated",
9
+ user: req.user,
10
+ });
11
+ });
12
+
13
+ export default router;
@@ -1,5 +1,4 @@
1
1
  import "dotenv/config";
2
-
3
2
  import { app } from "./app.js";
4
3
  import { env } from "./config/env.js";
5
4
  import { logger } from "./utils/logger.js";
@@ -1,4 +1,4 @@
1
- import { env } from "../config/env.js";
1
+ import { env } from "../config/env.ts";
2
2
 
3
3
  type LogLevel = "debug" | "info" | "warn" | "error" | "fatal";
4
4
 
@@ -2,18 +2,25 @@
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
4
  "module": "ESNext",
5
- "rootDir": "src",
6
- "outDir": "dist",
5
+ "moduleResolution": "bundler",
6
+ "rootDir": "./src",
7
+ "outDir": "./dist",
7
8
  "strict": true,
8
9
  "esModuleInterop": true,
9
10
  "forceConsistentCasingInFileNames": true,
10
11
  "skipLibCheck": true,
11
- "moduleResolution": "node",
12
12
  "resolveJsonModule": true,
13
13
  "allowJs": false,
14
- "noEmitOnError": true,
15
- "sourceMap": true
14
+ "noEmitOnError": false,
15
+ "sourceMap": true,
16
+ "declaration": false,
17
+ "allowImportingTsExtensions": true,
18
+ "noEmit": true
16
19
  },
17
- "include": ["src/**/*.ts"],
18
- "exclude": ["node_modules", "dist"]
20
+ "include": ["src/**/*"],
21
+ "exclude": ["node_modules", "dist"],
22
+ "ts-node": {
23
+ "esm": true,
24
+ "experimentalSpecifierResolution": "node"
25
+ }
19
26
  }
@@ -1,283 +0,0 @@
1
- # Error Handling Architecture Diagram
2
-
3
- ## Complete Error Flow
4
-
5
- ```
6
- ┌─────────────────────────────────────────────────────────────────────┐
7
- │ HTTP REQUEST │
8
- └──────────────────────────────────────┬──────────────────────────────┘
9
-
10
-
11
- ┌─────────────────────────────────────────────────────────────────────┐
12
- │ CORS & BODY PARSING MIDDLEWARE │
13
- └──────────────────────────────────────┬──────────────────────────────┘
14
-
15
-
16
- ┌─────────────────────────────────────────────────────────────────────┐
17
- │ REQUEST LOGGER MIDDLEWARE │
18
- │ (Logs: method, path, query, IP, user-agent) │
19
- └──────────────────────────────────────┬──────────────────────────────┘
20
-
21
-
22
- ┌─────────────────────────────────────────────────────────────────────┐
23
- │ VALIDATION MIDDLEWARE (optional) │
24
- │ │
25
- │ Validates with Zod schema → throws ValidationError if fails │
26
- └──────────────────────────────────────┬──────────────────────────────┘
27
-
28
-
29
- ┌─────────────────────────────────────────────────────────────────────┐
30
- │ ROUTE HANDLER (wrapped with asyncHandler) │
31
- │ │
32
- │ ┌────────────────────────────────────────────────────────────────┐ │
33
- │ │ asyncHandler(async (req, res) => { │ │
34
- │ │ // Your handler code │ │
35
- │ │ const user = await User.findById(req.params.id); │ │
36
- │ │ │ │
37
- │ │ if (!user) { │ │
38
- │ │ throw new NotFoundError("User", { id: req.params.id }); │ │
39
- │ │ } │ │
40
- │ │ │ │
41
- │ │ sendSuccess(res, user); │ │
42
- │ │ }) │ │
43
- │ └────────────────────────────────────────────────────────────────┘ │
44
- └────────┬────────────────────────────────────────────────────────────┘
45
-
46
- ├──→ Success? ──→ sendSuccess() ──→ [END: Response sent]
47
-
48
- └──→ Error thrown ✘ ──→ [Continue below]
49
-
50
-
51
- ┌─────────────────────────────────────────────────────────────────────┐
52
- │ GLOBAL ERROR HANDLER MIDDLEWARE │
53
- │ (This is where ALL errors flow!) │
54
- └────┬────────────────────────────────────────────────────────────────┘
55
-
56
-
57
- ┌─────────────────────────────────────────────────────────────────────┐
58
- │ ERROR NORMALIZATION │
59
- │ │
60
- │ if (err instanceof AppError) → Use as is │
61
- │ if (err instanceof ZodError) → Convert to ValidationError │
62
- │ if (err instanceof TypeError) → Convert to InternalServerError │
63
- │ if (err instanceof ReferenceError)→ Convert to InternalServerError │
64
- │ if (err instanceof SyntaxError) → Convert to InternalServerError │
65
- │ if (err instanceof RangeError) → Convert to InternalServerError │
66
- │ else → Wrap in InternalServerError │
67
- └────┬────────────────────────────────────────────────────────────────┘
68
-
69
-
70
- ┌─────────────────────────────────────────────────────────────────────┐
71
- │ ERROR CLASSIFICATION │
72
- │ │
73
- │ ┌─ Operational Error (isOperational: true) │
74
- │ │ ├─ ValidationError (422) │
75
- │ │ ├─ NotFoundError (404) │
76
- │ │ ├─ AuthenticationError (401) │
77
- │ │ ├─ AuthorizationError (403) │
78
- │ │ ├─ ConflictError (409) │
79
- │ │ └─ BadRequestError (400) │
80
- │ │ │
81
- │ └─ Programmer Error (isOperational: false) │
82
- │ └─ TypeError, ReferenceError, SyntaxError, etc. │
83
- └────┬────────────────────────────────────────────────────────────────┘
84
-
85
-
86
- ┌─────────────────────────────────────────────────────────────────────┐
87
- │ ERROR LOGGING │
88
- │ │
89
- │ If Operational Error: │
90
- │ ├─ Log as WARN level │
91
- │ ├─ Include: code, message, statusCode, method, path, IP │
92
- │ └─ NO stack trace (expected error) │
93
- │ │
94
- │ If Programmer Error: │
95
- │ ├─ Log as ERROR level │
96
- │ ├─ Include: code, message, statusCode, method, path, IP, stack │
97
- │ └─ YES full stack trace (for debugging) │
98
- └────┬────────────────────────────────────────────────────────────────┘
99
-
100
-
101
- ┌─────────────────────────────────────────────────────────────────────┐
102
- │ SEND ERROR RESPONSE │
103
- │ │
104
- │ If Production & Programmer Error: │
105
- │ ├─ { │
106
- │ │ success: false, │
107
- │ │ message: "Internal server error", │
108
- │ │ code: "INTERNAL_SERVER_ERROR", │
109
- │ │ timestamp: "..." │
110
- │ │ } │
111
- │ │ │
112
- │ └─ (Details hidden from client) │
113
- │ │
114
- │ If Development OR Operational Error: │
115
- │ ├─ { │
116
- │ │ success: false, │
117
- │ │ message: "Full error message", │
118
- │ │ code: "ERROR_CODE", │
119
- │ │ statusCode: 422, │
120
- │ │ context: { ... }, │
121
- │ │ errors: [ ... ], // for validation errors │
122
- │ │ timestamp: "..." │
123
- │ │ } │
124
- │ │ │
125
- │ └─ (Full details sent) │
126
- └────┬────────────────────────────────────────────────────────────────┘
127
-
128
-
129
- ┌─────────────────────────────────────────────────────────────────────┐
130
- │ HTTP RESPONSE SENT TO CLIENT │
131
- │ │
132
- │ Status Code: 400, 401, 403, 404, 409, 422, 500, etc. │
133
- │ Body: Consistent JSON error format │
134
- └─────────────────────────────────────────────────────────────────────┘
135
- ```
136
-
137
- ## Error Class Hierarchy
138
-
139
- ```
140
- Error (JavaScript)
141
-
142
- └── AppError (Base class)
143
-
144
- ├── ValidationError (422 - Input validation failed)
145
- ├── BadRequestError (400 - Malformed request)
146
- ├── AuthenticationError (401 - Auth failed)
147
- ├── AuthorizationError (403 - Permission denied)
148
- ├── NotFoundError (404 - Resource not found)
149
- ├── ConflictError (409 - Duplicate/conflict)
150
- └── InternalServerError (500 - Unexpected error)
151
- ```
152
-
153
- ## Middleware Stack Order
154
-
155
- ```
156
- Express App
157
-
158
- ├─ Trust Proxy
159
- ├─ CORS
160
- ├─ JSON Body Parser
161
- ├─ URL Encoded Parser
162
- ├─ Request Timeout Handler
163
-
164
- ├─ requestLogger (logs all requests)
165
-
166
- ├─ Routes:
167
- │ │
168
- │ ├─ validateRequest (optional, per route)
169
- │ │
170
- │ └─ Route Handler (MUST wrap with asyncHandler)
171
-
172
- └─ errorHandler (MUST BE LAST)
173
- └─ Catches all errors and sends JSON response
174
- ```
175
-
176
- ## Error Classification Decision Tree
177
-
178
- ```
179
- Error Thrown
180
-
181
- ┌───────────┴───────────┐
182
- │ │
183
- Is AppError? Is ZodError?
184
- │ │
185
- YES YES
186
- │ │
187
- ┌───────▼────────┐ ┌──────▼──────────┐
188
- │ Use as is │ │ Convert to │
189
- │ (already has │ │ ValidationError │
190
- │ isOperational)│ │ (422) │
191
- └─────────────────┘ └─────────────────┘
192
-
193
- ┌───────────────────────┴───────────────────────┐
194
- │ │
195
- Is Operational? Is Programmer Error?
196
- (isOperational: true) (Syntax, Type, Ref, Range)
197
- │ │
198
- YES YES
199
- │ │
200
- ┌──────────▼──────────┐ ┌──────────▼──────────┐
201
- │ Send full error │ │ Convert to │
202
- │ details to client │ │ InternalServerError │
203
- │ with code & context │ │ (500) │
204
- │ │ │ isOperational: false│
205
- │ Log as WARN │ │ │
206
- │ (no stack) │ │ Log as ERROR │
207
- │ │ │ WITH FULL STACK │
208
- └─────────────────────┘ │ │
209
- │ Hide details in │
210
- │ production │
211
- └─────────────────────┘
212
- ```
213
-
214
- ## Request-to-Response Timeline
215
-
216
- ```
217
- TIME LAYER ACTION
218
- ════ ═════════════════════ ════════════════════════════════════════
219
-
220
- T0 Network Request arrives at server
221
-
222
- T1 Express Middleware CORS, Body Parser, Request Logger
223
-
224
- T2 Route Handler validateRequest() - validates input
225
-
226
- T3 Route Handler Handler executes (wrapped with asyncHandler)
227
- ├─ Success: sendSuccess() → Response sent → T6
228
- └─ Error: Thrown → T4
229
-
230
- T4 asyncHandler Catches error, passes to next(error)
231
-
232
- T5 Error Handler Mw Normalizes error
233
- Classifies (operational vs programmer)
234
- Logs error with context
235
- Sanitizes response (production)
236
- Sends JSON response
237
-
238
- T6 Network Response sent to client
239
- ```
240
-
241
- ## Environment Behavior
242
-
243
- ```
244
- ┌──────────────────────┐ ┌──────────────────────┐
245
- │ DEVELOPMENT │ │ PRODUCTION │
246
- │ NODE_ENV=development│ │ NODE_ENV=production │
247
- └──────────┬───────────┘ └──────────┬───────────┘
248
- │ │
249
- │ Programmer Error: │ Programmer Error:
250
- │ ┌────────────────────────┐ │ ┌────────────────────────┐
251
- │ │ { │ │ │ { │
252
- │ │ success: false, │ │ │ success: false, │
253
- │ │ message: "TypeError: │ │ │ message: "Internal │
254
- │ │ x is undefined", │ │ │ server error", │
255
- │ │ code: "INTERNAL...", │ │ │ code: "INTERNAL...", │
256
- │ │ stack: "TypeError... │ │ │ timestamp: "..." │
257
- │ │ at handler.js:15..." │ │ │ } │
258
- │ │ } │ │ │ │
259
- │ └────────────────────────┘ │ └────────────────────────┘
260
- │ │
261
- │ Operational Error: │ Operational Error:
262
- │ (sent fully in both) │ (sent fully in both)
263
- │ ┌────────────────────────┐ │ ┌────────────────────────┐
264
- │ │ { │ │ │ { │
265
- │ │ success: false, │ │ │ success: false, │
266
- │ │ message: "User not │ │ │ message: "User not │
267
- │ │ found", │ │ │ found", │
268
- │ │ code: "NOT_FOUND", │ │ │ code: "NOT_FOUND", │
269
- │ │ context: {...} │ │ │ context: {...} │
270
- │ │ } │ │ │ } │
271
- │ └────────────────────────┘ │ └────────────────────────┘
272
- │ │
273
- │ Logging: │ Logging:
274
- │ Full details + stack │ Full details + stack
275
- │ (for development) │ (server-side only)
276
- │ │
277
- ```
278
-
279
- ---
280
-
281
- This architecture ensures that **every single error in your application flows through one place, gets properly classified, logged with full context, and returns a consistent JSON response to the client.**
282
-
283
- That's production-grade error handling. 🎯