create-xpress-backend 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/package.json +43 -0
- package/src/generator.js +50 -0
- package/src/index.js +154 -0
- package/src/templates/index.js +15 -0
- package/src/templates/js.js +519 -0
- package/src/templates/shared.js +283 -0
- package/src/templates/ts.js +587 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Files identical between JS and TS (or only trivially different).
|
|
5
|
+
*/
|
|
6
|
+
function buildSharedFiles({ projectName, port, includeFileUpload, includeAuth, language }) {
|
|
7
|
+
const isTs = language === 'ts';
|
|
8
|
+
const files = {};
|
|
9
|
+
|
|
10
|
+
// ─── .env & .env.example ──────────────────────────────────────────────────
|
|
11
|
+
const envContent = [
|
|
12
|
+
`NODE_ENV=development`,
|
|
13
|
+
`PORT=${port}`,
|
|
14
|
+
``,
|
|
15
|
+
`# Database`,
|
|
16
|
+
`DATABASE_URL="postgresql://postgres:admin@localhost:5432/${projectName}_db"`,
|
|
17
|
+
``,
|
|
18
|
+
`# JWT`,
|
|
19
|
+
`JWT_SECRET=your-super-secret-jwt-key-change-this`,
|
|
20
|
+
`JWT_EXPIRES_IN=7d`,
|
|
21
|
+
``,
|
|
22
|
+
...(includeFileUpload ? [`# File Upload`, `MAX_FILE_SIZE=10`, `UPLOAD_PATH=./uploads`, ``] : []),
|
|
23
|
+
`# Client`,
|
|
24
|
+
`CLIENT_URL=http://localhost:3000`,
|
|
25
|
+
`SERVER_URL=http://localhost:${port}`,
|
|
26
|
+
].join('\n');
|
|
27
|
+
|
|
28
|
+
files['.env'] = envContent;
|
|
29
|
+
files['.env.example'] = envContent;
|
|
30
|
+
|
|
31
|
+
// ─── .gitignore ───────────────────────────────────────────────────────────
|
|
32
|
+
files['.gitignore'] = [
|
|
33
|
+
'node_modules',
|
|
34
|
+
'.env',
|
|
35
|
+
'dist',
|
|
36
|
+
'uploads/*',
|
|
37
|
+
'!uploads/.gitkeep',
|
|
38
|
+
'*.log',
|
|
39
|
+
'.DS_Store',
|
|
40
|
+
].join('\n');
|
|
41
|
+
|
|
42
|
+
// ─── prisma.config (JS only — TS version is in ts.js) ────────────────────
|
|
43
|
+
if (!isTs) {
|
|
44
|
+
files['prisma.config.js'] = `const { defineConfig } = require('@prisma/config');
|
|
45
|
+
require('dotenv').config();
|
|
46
|
+
|
|
47
|
+
module.exports = defineConfig({
|
|
48
|
+
datasource: {
|
|
49
|
+
url: process.env.DATABASE_URL,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ─── prisma/schema.prisma ─────────────────────────────────────────────────
|
|
56
|
+
const schemaLines = [
|
|
57
|
+
`// prisma/schema.prisma`,
|
|
58
|
+
`generator client {`,
|
|
59
|
+
` provider = "prisma-client-js"`,
|
|
60
|
+
`}`,
|
|
61
|
+
``,
|
|
62
|
+
`datasource db {`,
|
|
63
|
+
` provider = "postgresql"`,
|
|
64
|
+
`}`,
|
|
65
|
+
``,
|
|
66
|
+
`model User {`,
|
|
67
|
+
` id String @id @default(uuid())`,
|
|
68
|
+
` email String @unique`,
|
|
69
|
+
` name String?`,
|
|
70
|
+
...(includeAuth ? [` password String?`] : []),
|
|
71
|
+
...(includeFileUpload ? [` files File[]`] : []),
|
|
72
|
+
` createdAt DateTime @default(now())`,
|
|
73
|
+
` updatedAt DateTime @updatedAt`,
|
|
74
|
+
`}`,
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
if (includeFileUpload) {
|
|
78
|
+
schemaLines.push(
|
|
79
|
+
``,
|
|
80
|
+
`model File {`,
|
|
81
|
+
` id String @id @default(cuid())`,
|
|
82
|
+
` filename String`,
|
|
83
|
+
` originalName String`,
|
|
84
|
+
` path String`,
|
|
85
|
+
` size Int`,
|
|
86
|
+
` mimetype String`,
|
|
87
|
+
` userId String`,
|
|
88
|
+
` user User @relation(fields: [userId], references: [id], onDelete: Cascade)`,
|
|
89
|
+
` createdAt DateTime @default(now())`,
|
|
90
|
+
` updatedAt DateTime @updatedAt`,
|
|
91
|
+
``,
|
|
92
|
+
` @@map("files")`,
|
|
93
|
+
`}`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
files['prisma/schema.prisma'] = schemaLines.join('\n') + '\n';
|
|
98
|
+
|
|
99
|
+
// ─── seed file ────────────────────────────────────────────────────────────
|
|
100
|
+
if (isTs) {
|
|
101
|
+
files['src/database/seed.ts'] = `// src/database/seed.ts
|
|
102
|
+
import prisma from './prisma';
|
|
103
|
+
|
|
104
|
+
async function main() {
|
|
105
|
+
const email = 'admin@${projectName}.com';
|
|
106
|
+
const existing = await prisma.user.findUnique({ where: { email } });
|
|
107
|
+
|
|
108
|
+
if (!existing) {
|
|
109
|
+
await prisma.user.create({ data: { email, name: 'Admin User' } });
|
|
110
|
+
console.log(\`Seed: admin user \${email} created.\`);
|
|
111
|
+
} else {
|
|
112
|
+
console.log(\`Seed: admin user \${email} already exists. Skipping.\`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main()
|
|
117
|
+
.catch((e) => { console.error('Seed error:', e); process.exit(1); })
|
|
118
|
+
.finally(async () => { await prisma.$disconnect(); });
|
|
119
|
+
`;
|
|
120
|
+
} else {
|
|
121
|
+
files['src/database/seed.js'] = `// src/database/seed.js
|
|
122
|
+
const prisma = require('./prisma');
|
|
123
|
+
|
|
124
|
+
async function main() {
|
|
125
|
+
const email = 'admin@${projectName}.com';
|
|
126
|
+
const existing = await prisma.user.findUnique({ where: { email } });
|
|
127
|
+
|
|
128
|
+
if (!existing) {
|
|
129
|
+
await prisma.user.create({ data: { email, name: 'Admin User' } });
|
|
130
|
+
console.log(\`Seed: admin user \${email} created.\`);
|
|
131
|
+
} else {
|
|
132
|
+
console.log(\`Seed: admin user \${email} already exists. Skipping.\`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
main()
|
|
137
|
+
.catch((e) => { console.error('Seed error:', e); process.exit(1); })
|
|
138
|
+
.finally(async () => { await prisma.$disconnect(); });
|
|
139
|
+
`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ─── Per-project README builder ───────────────────────────────────────────────
|
|
146
|
+
function buildReadme({ projectName, port, includeFileUpload, includeAuth, language }) {
|
|
147
|
+
const isTs = language === 'ts';
|
|
148
|
+
const ext = isTs ? 'ts' : 'js';
|
|
149
|
+
const devCmd = isTs ? 'npm run dev' : 'npm run dev';
|
|
150
|
+
const seedCmd = isTs ? 'npm run db:seed' : 'npm run db:seed';
|
|
151
|
+
|
|
152
|
+
const features = [
|
|
153
|
+
`⚡ Express 4 with security middleware (Helmet, CORS)`,
|
|
154
|
+
`🗄️ Prisma 7 ORM with PostgreSQL (driver adapter)`,
|
|
155
|
+
`✅ Joi request validation`,
|
|
156
|
+
`🌱 Database seeding script`,
|
|
157
|
+
...(includeFileUpload ? [`📁 File upload system (Multer)`] : []),
|
|
158
|
+
...(includeAuth ? [`🔐 JWT authentication (register / login)`] : []),
|
|
159
|
+
`🔄 Graceful shutdown`,
|
|
160
|
+
`🏥 Health check endpoint`,
|
|
161
|
+
...(isTs ? [`🔷 Full TypeScript support with strict mode`] : []),
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
const uploadRoutes = includeFileUpload
|
|
165
|
+
? `| \`POST\` | \`/api/demo/upload\` | Upload a file |
|
|
166
|
+
| \`GET\` | \`/api/demo/files/all\` | List uploaded files |
|
|
167
|
+
| \`DELETE\` | \`/api/demo/files/:fileId\` | Delete a file |`
|
|
168
|
+
: '';
|
|
169
|
+
|
|
170
|
+
const authRoutes = includeAuth
|
|
171
|
+
? `\n### Auth\n\n| Method | Path | Description |\n|--------|------|-------------|\n| \`POST\` | \`/api/auth/register\` | Register a user |\n| \`POST\` | \`/api/auth/login\` | Login |\n`
|
|
172
|
+
: '';
|
|
173
|
+
|
|
174
|
+
const buildSection = isTs
|
|
175
|
+
? `\n## Build\n\n\`\`\`bash\nnpm run build # compiles TypeScript → dist/\nnpm start # runs compiled output\n\`\`\`\n`
|
|
176
|
+
: '';
|
|
177
|
+
|
|
178
|
+
const tsScripts = isTs
|
|
179
|
+
? `| \`npm run build\` | Compile TypeScript to \`dist/\` |
|
|
180
|
+
| \`npm start\` | Run compiled production build |` : '';
|
|
181
|
+
|
|
182
|
+
const structureExtras = isTs
|
|
183
|
+
? `│ ├── types/\n│ │ └── express.d.ts ← req.user type augmentation\n` : '';
|
|
184
|
+
|
|
185
|
+
return `# ${projectName}
|
|
186
|
+
|
|
187
|
+
> Scaffolded with [create-xpress-backend](https://github.com/ayushsolanki29/create-xpress-backend) · ${isTs ? 'TypeScript' : 'JavaScript'}
|
|
188
|
+
|
|
189
|
+
## Stack
|
|
190
|
+
|
|
191
|
+
- **Runtime** — Node.js ≥ 18
|
|
192
|
+
- **Language** — ${isTs ? 'TypeScript 5 (strict mode)' : 'JavaScript (CommonJS)'}
|
|
193
|
+
- **Framework** — Express 4
|
|
194
|
+
- **ORM** — Prisma 7 + PostgreSQL (driver adapter)
|
|
195
|
+
- **Validation** — Joi
|
|
196
|
+
${includeAuth ? `- **Auth** — JWT (jsonwebtoken + bcryptjs)\n` : ''}${includeFileUpload ? `- **Uploads** — Multer\n` : ''}
|
|
197
|
+
## Features
|
|
198
|
+
|
|
199
|
+
${features.map((f) => `- ${f}`).join('\n')}
|
|
200
|
+
|
|
201
|
+
## Quick Start
|
|
202
|
+
|
|
203
|
+
\`\`\`bash
|
|
204
|
+
npm install
|
|
205
|
+
|
|
206
|
+
# configure DATABASE_URL in .env, then:
|
|
207
|
+
npm run db:push
|
|
208
|
+
${seedCmd} # optional
|
|
209
|
+
${devCmd}
|
|
210
|
+
\`\`\`
|
|
211
|
+
|
|
212
|
+
Server starts on **http://localhost:${port}**
|
|
213
|
+
${buildSection}
|
|
214
|
+
## Scripts
|
|
215
|
+
|
|
216
|
+
| Command | Description |
|
|
217
|
+
|-----------------------|--------------------------------------|
|
|
218
|
+
| \`npm run dev\` | Start dev server with auto-reload |
|
|
219
|
+
${tsScripts ? tsScripts + '\n' : ''}| \`npm run db:push\` | Push Prisma schema to the database |
|
|
220
|
+
| \`npm run db:generate\` | Regenerate Prisma Client |
|
|
221
|
+
| \`npm run db:dev\` | Push schema + generate in one step |
|
|
222
|
+
| \`npm run db:seed\` | Seed initial data |
|
|
223
|
+
| \`npm run db:studio\` | Open Prisma Studio |
|
|
224
|
+
| \`npm run db:reset\` | Force-reset the database schema |
|
|
225
|
+
|
|
226
|
+
## API Reference
|
|
227
|
+
|
|
228
|
+
### Demo
|
|
229
|
+
|
|
230
|
+
| Method | Path | Description |
|
|
231
|
+
|----------|-------------------|-----------------|
|
|
232
|
+
| \`POST\` | \`/api/demo\` | Create a record |
|
|
233
|
+
| \`GET\` | \`/api/demo\` | Get all records |
|
|
234
|
+
| \`GET\` | \`/api/demo/:id\` | Get by ID |
|
|
235
|
+
| \`PUT\` | \`/api/demo/:id\` | Update |
|
|
236
|
+
| \`DELETE\` | \`/api/demo/:id\` | Delete |
|
|
237
|
+
${uploadRoutes ? uploadRoutes + '\n' : ''}
|
|
238
|
+
${authRoutes}
|
|
239
|
+
### Health
|
|
240
|
+
|
|
241
|
+
| Method | Path | Description |
|
|
242
|
+
|--------|-----------|---------------------|
|
|
243
|
+
| \`GET\` | \`/health\` | Server health check |
|
|
244
|
+
|
|
245
|
+
## Project Structure
|
|
246
|
+
|
|
247
|
+
\`\`\`
|
|
248
|
+
${projectName}/
|
|
249
|
+
├── prisma/
|
|
250
|
+
│ └── schema.prisma
|
|
251
|
+
├── src/
|
|
252
|
+
│ ├── app.${ext}
|
|
253
|
+
│ ├── server.${ext}
|
|
254
|
+
${structureExtras}│ ├── database/
|
|
255
|
+
│ │ ├── prisma.${ext}
|
|
256
|
+
│ │ └── seed.${ext}
|
|
257
|
+
│ ├── middleware/
|
|
258
|
+
│ │ ├── validate.${ext}
|
|
259
|
+
${includeFileUpload ? `│ │ ├── upload.${ext}\n` : ''}${includeAuth ? `│ │ └── auth.${ext}\n` : ''}│ └── modules/
|
|
260
|
+
│ ├── index.${ext}
|
|
261
|
+
│ ├── demo/
|
|
262
|
+
${includeAuth ? `│ └── auth/\n` : ''}${isTs ? `├── tsconfig.json\n` : ''}├── .env
|
|
263
|
+
├── .env.example
|
|
264
|
+
└── package.json
|
|
265
|
+
\`\`\`
|
|
266
|
+
|
|
267
|
+
## Environment Variables
|
|
268
|
+
|
|
269
|
+
| Variable | Description | Default |
|
|
270
|
+
|------------------|--------------------------------|----------|
|
|
271
|
+
| \`PORT\` | Server port | \`${port}\` |
|
|
272
|
+
| \`DATABASE_URL\` | PostgreSQL connection string | — |
|
|
273
|
+
| \`JWT_SECRET\` | Secret key for JWT signing | — |
|
|
274
|
+
| \`JWT_EXPIRES_IN\` | Token expiry duration | \`7d\` |
|
|
275
|
+
| \`CLIENT_URL\` | Allowed CORS origin | \`*\` |
|
|
276
|
+
${includeFileUpload ? `| \`MAX_FILE_SIZE\` | Max upload size in MB | \`10\` |\n` : ''}
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = { buildSharedFiles, buildReadme };
|