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.
@@ -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 };