create-charcole 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/LICENSE +21 -0
- package/README.md +398 -0
- package/bin/index.js +62 -0
- package/package.json +24 -0
- package/template/.env.example +8 -0
- package/template/ARCHITECTURE_DIAGRAMS.md +283 -0
- package/template/CHECKLIST.md +279 -0
- package/template/COMPLETE.md +405 -0
- package/template/ERROR_HANDLING.md +393 -0
- package/template/IMPLEMENTATION.md +368 -0
- package/template/IMPLEMENTATION_COMPLETE.md +363 -0
- package/template/INDEX.md +290 -0
- package/template/QUICK_REFERENCE.md +270 -0
- package/template/README.md +855 -0
- package/template/package-lock.json +1253 -0
- package/template/package.json +28 -0
- package/template/src/app.js +75 -0
- package/template/src/config/constants.js +20 -0
- package/template/src/config/env.js +26 -0
- package/template/src/middlewares/errorHandler.js +180 -0
- package/template/src/middlewares/requestLogger.js +33 -0
- package/template/src/middlewares/validateRequest.js +42 -0
- package/template/src/modules/health/controller.js +50 -0
- package/template/src/routes.js +17 -0
- package/template/src/server.js +38 -0
- package/template/src/utils/AppError.js +182 -0
- package/template/src/utils/logger.js +73 -0
- package/template/src/utils/response.js +51 -0
- package/template/test-api.js +100 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sheraz Manzoor
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# Charcole API
|
|
2
|
+
|
|
3
|
+
> **Production-grade Node.js Express API with enterprise-level error handling, Zod validation, and structured logging.**
|
|
4
|
+
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](https://expressjs.com/)
|
|
7
|
+
[](https://zod.dev/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
## 🎯 What This Is
|
|
11
|
+
|
|
12
|
+
A **production-ready Node.js Express backend** with:
|
|
13
|
+
|
|
14
|
+
- ✅ **Centralized Error Handling** - Every error flows through one place
|
|
15
|
+
- ✅ **Error Classification** - Operational vs Programmer errors distinguished
|
|
16
|
+
- ✅ **Zod Validation** - Type-safe schema validation with automatic error formatting
|
|
17
|
+
- ✅ **Structured Logging** - Color-coded logs with context and stack traces
|
|
18
|
+
- ✅ **Consistent JSON Responses** - Standardized format across all endpoints
|
|
19
|
+
- ✅ **Production-Safe** - Internal details hidden from clients in production
|
|
20
|
+
- ✅ **Async Error Handling** - Promise rejection leaks prevented with asyncHandler
|
|
21
|
+
- ✅ **Graceful Shutdown** - Proper cleanup on SIGTERM/SIGINT
|
|
22
|
+
- ✅ **Request Logging** - Method, path, status, duration, IP automatically tracked
|
|
23
|
+
- ✅ **Unhandled Exception Catching** - All edge cases caught and logged
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
### Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Create your charcole app now
|
|
31
|
+
npx create-charcole@latest charcole-demo
|
|
32
|
+
|
|
33
|
+
# Configure environment
|
|
34
|
+
cp .env.example .env
|
|
35
|
+
|
|
36
|
+
# Start development server (with auto-reload)
|
|
37
|
+
npm run dev
|
|
38
|
+
|
|
39
|
+
# OR start production server
|
|
40
|
+
npm start
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Server runs on `http://localhost:3000` by default.
|
|
44
|
+
|
|
45
|
+
## 📋 Key Features
|
|
46
|
+
|
|
47
|
+
### 🛡️ Enterprise-Grade Error Handling
|
|
48
|
+
|
|
49
|
+
**No More `res.status(500).json(...)`**
|
|
50
|
+
|
|
51
|
+
Every error in your application flows through a centralized global error handler that:
|
|
52
|
+
|
|
53
|
+
1. **Normalizes** all error types (ZodError, TypeError, custom AppError, etc.)
|
|
54
|
+
2. **Classifies** errors as operational (expected) or programmer (bugs)
|
|
55
|
+
3. **Logs** appropriately (WARN for operational, ERROR with stack for programmer)
|
|
56
|
+
4. **Sanitizes** responses (hides details in production, shows context in dev)
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
// ✅ Throw AppError - ALWAYS
|
|
60
|
+
throw new NotFoundError("User", { id: userId });
|
|
61
|
+
throw new ValidationError("Invalid input", errors);
|
|
62
|
+
throw new ConflictError("Email already exists");
|
|
63
|
+
|
|
64
|
+
// ❌ Never do this
|
|
65
|
+
res.status(404).json({ error: "Not found" });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 🔐 Type-Safe Validation
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
import { z } from "zod";
|
|
72
|
+
import { validateRequest } from "./middlewares/validateRequest.js";
|
|
73
|
+
|
|
74
|
+
const createUserSchema = z.object({
|
|
75
|
+
body: z.object({
|
|
76
|
+
email: z.string().email(),
|
|
77
|
+
name: z.string().min(1),
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
router.post("/users", validateRequest(createUserSchema), handler);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 📝 Structured Logging
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
import { logger } from "./utils/logger.js";
|
|
88
|
+
|
|
89
|
+
logger.debug("Debug message", { data: true });
|
|
90
|
+
logger.info("Info message", { data: true });
|
|
91
|
+
logger.warn("Warning message", { data: true });
|
|
92
|
+
logger.error("Error message", { data: true });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 📊 Consistent JSON Responses
|
|
96
|
+
|
|
97
|
+
All responses follow the same format:
|
|
98
|
+
|
|
99
|
+
**Success:**
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"success": true,
|
|
104
|
+
"message": "User created successfully",
|
|
105
|
+
"data": { "id": "123", "name": "John" },
|
|
106
|
+
"timestamp": "2024-01-20T12:00:00.000Z"
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Error:**
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"success": false,
|
|
115
|
+
"message": "User not found",
|
|
116
|
+
"code": "NOT_FOUND",
|
|
117
|
+
"statusCode": 404,
|
|
118
|
+
"context": { "id": "999" },
|
|
119
|
+
"timestamp": "2024-01-20T12:00:00.000Z"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Validation Error:**
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"success": false,
|
|
128
|
+
"message": "Validation failed",
|
|
129
|
+
"code": "VALIDATION_ERROR",
|
|
130
|
+
"statusCode": 422,
|
|
131
|
+
"errors": [
|
|
132
|
+
{ "field": "email", "message": "Invalid email", "code": "invalid_email" }
|
|
133
|
+
],
|
|
134
|
+
"timestamp": "2024-01-20T12:00:00.000Z"
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 🏗️ Error Classes
|
|
139
|
+
|
|
140
|
+
Use these specialized error classes:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
import {
|
|
144
|
+
AppError, // Base class
|
|
145
|
+
ValidationError, // 422 - Input validation failed
|
|
146
|
+
BadRequestError, // 400 - Malformed request
|
|
147
|
+
AuthenticationError, // 401 - Invalid credentials
|
|
148
|
+
AuthorizationError, // 403 - Permission denied
|
|
149
|
+
NotFoundError, // 404 - Resource not found
|
|
150
|
+
ConflictError, // 409 - Duplicate/conflict
|
|
151
|
+
InternalServerError, // 500 - Unexpected error
|
|
152
|
+
} from "./middlewares/errorHandler.js";
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 📚 Documentation
|
|
156
|
+
|
|
157
|
+
| Document | Purpose |
|
|
158
|
+
| ------------------------------------------------- | --------------------------------- |
|
|
159
|
+
| [Getting Started](template/README.md) | Setup & directory structure guide |
|
|
160
|
+
| [Quick Reference](QUICK_REFERENCE.md) | Quick patterns & golden rules |
|
|
161
|
+
| [Error Handling Guide](ERROR_HANDLING.md) | Comprehensive error documentation |
|
|
162
|
+
| [Architecture Diagrams](ARCHITECTURE_DIAGRAMS.md) | Visual system architecture |
|
|
163
|
+
| [Full Implementation](IMPLEMENTATION_COMPLETE.md) | Complete implementation details |
|
|
164
|
+
|
|
165
|
+
## 🎓 4 Golden Rules
|
|
166
|
+
|
|
167
|
+
1. **Wrap async handlers** with `asyncHandler`
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
router.get("/users/:id", asyncHandler(async (req, res) => { ... }))
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
2. **Throw AppError** (never use `res.status().json()`)
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
throw new NotFoundError("User", { id });
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
3. **Validate requests** with `validateRequest`
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
router.post("/users", validateRequest(schema), handler);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
4. **Send success** with `sendSuccess`
|
|
186
|
+
```javascript
|
|
187
|
+
sendSuccess(res, data, 201, "User created");
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 📂 Project Structure
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
src/
|
|
194
|
+
├── config/
|
|
195
|
+
│ ├── env.js # Environment validation with Zod
|
|
196
|
+
│ └── constants.js # HTTP status codes & error messages
|
|
197
|
+
├── middlewares/
|
|
198
|
+
│ ├── errorHandler.js # ⭐ Global error handler + asyncHandler
|
|
199
|
+
│ ├── validateRequest.js # Request validation middleware
|
|
200
|
+
│ └── requestLogger.js # Request logging
|
|
201
|
+
├── modules/
|
|
202
|
+
│ └── health/
|
|
203
|
+
│ └── controller.js # Example handlers
|
|
204
|
+
├── utils/
|
|
205
|
+
│ ├── AppError.js # ⭐ Error class hierarchy
|
|
206
|
+
│ ├── logger.js # Structured logging
|
|
207
|
+
│ └── response.js # Success response helpers
|
|
208
|
+
├── app.js # Express app setup
|
|
209
|
+
├── routes.js # API routes
|
|
210
|
+
└── server.js # Server entry point
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 🚀 Running
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Development (with auto-reload and full logging)
|
|
217
|
+
npm run dev
|
|
218
|
+
|
|
219
|
+
# Production (optimized, minimal logging)
|
|
220
|
+
npm start
|
|
221
|
+
|
|
222
|
+
# Test API endpoints
|
|
223
|
+
node test-api.js
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## 🔧 Configuration
|
|
227
|
+
|
|
228
|
+
Environment variables (see `.env.example`):
|
|
229
|
+
|
|
230
|
+
```env
|
|
231
|
+
NODE_ENV=development # development, production, test
|
|
232
|
+
PORT=3000 # Server port
|
|
233
|
+
LOG_LEVEL=info # debug, info, warn, error
|
|
234
|
+
CORS_ORIGIN=* # CORS allowed origins
|
|
235
|
+
REQUEST_TIMEOUT=30000 # Request timeout in milliseconds
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## 💻 Example: Create User Endpoint
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
import { asyncHandler, ConflictError } from "./middlewares/errorHandler.js";
|
|
242
|
+
import { validateRequest } from "./middlewares/validateRequest.js";
|
|
243
|
+
import { sendSuccess } from "./utils/response.js";
|
|
244
|
+
import { z } from "zod";
|
|
245
|
+
|
|
246
|
+
// 1. Define validation schema
|
|
247
|
+
const createUserSchema = z.object({
|
|
248
|
+
body: z.object({
|
|
249
|
+
email: z.string().email("Invalid email"),
|
|
250
|
+
name: z.string().min(1, "Name required").max(100),
|
|
251
|
+
}),
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// 2. Define handler (wrapped with asyncHandler)
|
|
255
|
+
export const createUser = asyncHandler(async (req, res) => {
|
|
256
|
+
const { email, name } = req.validatedData.body;
|
|
257
|
+
|
|
258
|
+
// Check for duplicate
|
|
259
|
+
const exists = await User.findOne({ email });
|
|
260
|
+
if (exists) {
|
|
261
|
+
throw new ConflictError("Email already exists", { email });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Create user (any error is automatically caught)
|
|
265
|
+
const user = await User.create({ email, name });
|
|
266
|
+
|
|
267
|
+
// Send success
|
|
268
|
+
sendSuccess(res, user, 201, "User created successfully");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// 3. Use in routes
|
|
272
|
+
router.post("/users", validateRequest(createUserSchema), createUser);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Results:**
|
|
276
|
+
|
|
277
|
+
- ✅ Valid request → 201 with user data
|
|
278
|
+
- ✅ Invalid email → 422 with field errors
|
|
279
|
+
- ✅ Duplicate email → 409 conflict
|
|
280
|
+
- ✅ Database error → 500 (logged, generic message sent in prod)
|
|
281
|
+
|
|
282
|
+
## 🌐 API Endpoints
|
|
283
|
+
|
|
284
|
+
All endpoints follow the same error handling pattern:
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
GET / # Root - API info
|
|
288
|
+
GET /api/health # Health check
|
|
289
|
+
POST /api/items # Create item (example)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## ✨ What Makes This Special
|
|
293
|
+
|
|
294
|
+
Unlike typical Express APIs, Charcole:
|
|
295
|
+
|
|
296
|
+
- ✅ **Distinguishes operational from programmer errors** - Different handling for expected vs unexpected errors
|
|
297
|
+
- ✅ **Never leaks internal details** - Production-safe error responses
|
|
298
|
+
- ✅ **Catches all async errors** - No promise rejections leak
|
|
299
|
+
- ✅ **Logs with full context** - Debugging is easy
|
|
300
|
+
- ✅ **Validates everything** - Zod integration prevents bad data
|
|
301
|
+
- ✅ **Consistent responses** - Predictable format for every endpoint
|
|
302
|
+
- ✅ **Production-ready** - Graceful shutdown, signal handling, etc.
|
|
303
|
+
|
|
304
|
+
## 🔄 Error Flow
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
Request arrives
|
|
308
|
+
↓
|
|
309
|
+
Handler (wrapped with asyncHandler)
|
|
310
|
+
├─ Success → sendSuccess() → Response sent ✓
|
|
311
|
+
└─ Error thrown ✘
|
|
312
|
+
↓
|
|
313
|
+
Global error handler catches it
|
|
314
|
+
↓
|
|
315
|
+
Error normalized & classified
|
|
316
|
+
↓
|
|
317
|
+
Logged (WARN for operational, ERROR with stack for programmer)
|
|
318
|
+
↓
|
|
319
|
+
Consistent JSON response sent
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 📊 Logging Examples
|
|
323
|
+
|
|
324
|
+
### Operational Error (Expected)
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
[2024-01-20T12:00:00.000Z] WARN: Operational Error: NOT_FOUND
|
|
328
|
+
{ "code": "NOT_FOUND", "message": "User not found", "statusCode": 404 }
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Programmer Error (Bug)
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
[2024-01-20T12:00:00.000Z] ERROR: Programmer Error: REFERENCE_ERROR
|
|
335
|
+
{ "code": "REFERENCE_ERROR", "message": "user is not defined" }
|
|
336
|
+
ReferenceError: user is not defined
|
|
337
|
+
at handler.js:15:3
|
|
338
|
+
...
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## 🛠️ Development
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# Install dependencies
|
|
345
|
+
npm install
|
|
346
|
+
|
|
347
|
+
# Start dev server with auto-reload
|
|
348
|
+
npm run dev
|
|
349
|
+
|
|
350
|
+
# Check for syntax errors
|
|
351
|
+
npm run lint
|
|
352
|
+
|
|
353
|
+
# Run tests
|
|
354
|
+
npm test
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## 📦 Dependencies
|
|
358
|
+
|
|
359
|
+
- **Express** - Web framework
|
|
360
|
+
- **Zod** - Schema validation
|
|
361
|
+
- **CORS** - Cross-origin requests
|
|
362
|
+
- **dotenv** - Environment variables
|
|
363
|
+
- **nodemon** - Auto-reload (dev only)
|
|
364
|
+
|
|
365
|
+
## 🚢 Production Checklist
|
|
366
|
+
|
|
367
|
+
Before deploying:
|
|
368
|
+
|
|
369
|
+
- [ ] Set `NODE_ENV=production`
|
|
370
|
+
- [ ] Configure `CORS_ORIGIN` for your domain
|
|
371
|
+
- [ ] Set `LOG_LEVEL=warn` or higher
|
|
372
|
+
- [ ] Add database connection
|
|
373
|
+
- [ ] Implement authentication
|
|
374
|
+
- [ ] Add rate limiting
|
|
375
|
+
- [ ] Set up error monitoring (e.g., Sentry)
|
|
376
|
+
- [ ] Configure reverse proxy (nginx/apache)
|
|
377
|
+
- [ ] Test all error scenarios
|
|
378
|
+
- [ ] Verify no secrets in error responses
|
|
379
|
+
|
|
380
|
+
## 🤝 Contributing
|
|
381
|
+
|
|
382
|
+
Contributions welcome! Please:
|
|
383
|
+
|
|
384
|
+
1. Follow the error handling patterns
|
|
385
|
+
2. Always use `asyncHandler` for async handlers
|
|
386
|
+
3. Throw `AppError` instances for errors
|
|
387
|
+
4. Include context in errors
|
|
388
|
+
5. Add tests for new features
|
|
389
|
+
|
|
390
|
+
## 📄 License
|
|
391
|
+
|
|
392
|
+
ISC
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
**Made for teams that care about code quality and production reliability.** 🚀
|
|
397
|
+
|
|
398
|
+
Need help? See the [Getting Started Guide](template/README.md) or [Full Documentation](ERROR_HANDLING.md).
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const projectName = process.argv[2];
|
|
7
|
+
|
|
8
|
+
if (!projectName) {
|
|
9
|
+
console.error("❌ Please provide a project name.");
|
|
10
|
+
console.error("Usage: npx create-charcole my-backend");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const currentDir = process.cwd();
|
|
15
|
+
const targetDir = path.join(currentDir, projectName);
|
|
16
|
+
const templateDir = path.join(__dirname, "..", "template");
|
|
17
|
+
|
|
18
|
+
if (fs.existsSync(targetDir)) {
|
|
19
|
+
console.error(`❌ Folder "${projectName}" already exists.`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function copyDir(src, dest) {
|
|
24
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
25
|
+
|
|
26
|
+
for (const file of fs.readdirSync(src)) {
|
|
27
|
+
const srcPath = path.join(src, file);
|
|
28
|
+
const destPath = path.join(dest, file);
|
|
29
|
+
|
|
30
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
31
|
+
copyDir(srcPath, destPath);
|
|
32
|
+
} else {
|
|
33
|
+
fs.copyFileSync(srcPath, destPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
console.log("🔥 Creating Charcole app...");
|
|
40
|
+
|
|
41
|
+
copyDir(templateDir, targetDir);
|
|
42
|
+
|
|
43
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
44
|
+
if (fs.existsSync(pkgPath)) {
|
|
45
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
46
|
+
pkg.name = projectName;
|
|
47
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log("✅ Charcole app created successfully!");
|
|
51
|
+
console.log("");
|
|
52
|
+
console.log("Next steps:");
|
|
53
|
+
console.log(` cd ${projectName}`);
|
|
54
|
+
console.log(" npm install");
|
|
55
|
+
console.log(" npm run dev");
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("🧱 Built with Charcole — Express, but engineered.");
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.error("❌ Failed to create Charcole app.");
|
|
60
|
+
console.error(err.message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-charcole",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Production-ready Express backend starter with engineering guardrails.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Sheraz Manzoor",
|
|
8
|
+
"email": "sheraz.dev121@gmail.com"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"create-charcole": "bin/index.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"express",
|
|
15
|
+
"backend",
|
|
16
|
+
"starter",
|
|
17
|
+
"boilerplate",
|
|
18
|
+
"production",
|
|
19
|
+
"charcole"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=16"
|
|
23
|
+
}
|
|
24
|
+
}
|