create-wabck 1.0.0 → 1.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.
@@ -215,19 +215,25 @@ ${database === 'mongodb' ? " mongoUri: process.env.MONGODB_URI || '',\n" : '
215
215
  `;
216
216
  }
217
217
 
218
- /** Generate src/config/swagger.js */
219
- export function swagger(options) {
218
+ /** Generate src/config/swagger.js or swagger.ts */
219
+ export function swaggerConfig(options) {
220
220
  const { projectName, language } = options;
221
221
  const isTS = language === 'typescript';
222
+ const ext = isTS ? 'ts' : 'js';
222
223
 
223
224
  return `import swaggerJsdoc from 'swagger-jsdoc';
225
+ import swaggerUi from 'swagger-ui-express';
224
226
  import { readFileSync } from 'fs';
225
227
  import { fileURLToPath } from 'url';
226
228
  import path from 'path';
227
-
229
+ ${isTS ? `import type { Express } from 'express';\n` : ''}
228
230
  const __filename = fileURLToPath(import.meta.url);
229
231
  const __dirname = path.dirname(__filename);
230
232
 
233
+ // ─────────────────────────────────────────────────────────────────────────────
234
+ // Swagger / OpenAPI 3.0 Configuration
235
+ // ─────────────────────────────────────────────────────────────────────────────
236
+
231
237
  // Read version from package.json
232
238
  let version = '1.0.0';
233
239
  try {
@@ -235,37 +241,82 @@ try {
235
241
  version = pkg.version;
236
242
  } catch { /* use default */ }
237
243
 
238
- const options = {
239
- definition: {
240
- openapi: '3.0.0',
241
- info: {
242
- title: '${projectName} API',
243
- version,
244
- description: 'Auto-generated API documentation for ${projectName}',
245
- license: { name: 'MIT' },
246
- contact: { name: '${projectName} Support' },
244
+ const swaggerDefinition = {
245
+ openapi: '3.0.0',
246
+ info: {
247
+ title: '${projectName} API',
248
+ version,
249
+ description: 'REST API documentation for ${projectName}',
250
+ license: { name: 'MIT' },
251
+ contact: { name: '${projectName} Team' },
252
+ },
253
+ servers: [
254
+ { url: \`http://localhost:\${process.env.PORT || 5000}/api/v1\`, description: 'Development' },
255
+ { url: '/api/v1', description: 'Relative (proxy-friendly)' },
256
+ ],
257
+ components: {
258
+ securitySchemes: {
259
+ bearerAuth: {
260
+ type: 'http',
261
+ scheme: 'bearer',
262
+ bearerFormat: 'JWT',
263
+ description: 'Enter your JWT token. Example: Bearer eyJhbGci...',
264
+ },
247
265
  },
248
- servers: [
249
- { url: \`http://localhost:\${process.env.PORT || 5000}/api/v1\`, description: 'Development' },
250
- ],
251
- components: {
252
- securitySchemes: {
253
- bearerAuth: {
254
- type: 'http',
255
- scheme: 'bearer',
256
- bearerFormat: 'JWT',
266
+ schemas: {
267
+ ApiResponse: {
268
+ type: 'object',
269
+ properties: {
270
+ success: { type: 'boolean' },
271
+ statusCode: { type: 'integer' },
272
+ message: { type: 'string' },
273
+ data: { },
274
+ },
275
+ },
276
+ ApiError: {
277
+ type: 'object',
278
+ properties: {
279
+ success: { type: 'boolean', example: false },
280
+ statusCode: { type: 'integer' },
281
+ message: { type: 'string' },
282
+ errors: { type: 'array', items: { type: 'string' } },
257
283
  },
258
284
  },
259
285
  },
260
- security: [{ bearerAuth: [] }],
261
286
  },
262
- // Pick up JSDoc @swagger annotations from all route files
287
+ security: [{ bearerAuth: [] }],
288
+ };
289
+
290
+ const swaggerOptions = {
291
+ definition: swaggerDefinition,
292
+ // Scans all route files for @swagger JSDoc annotations
263
293
  apis: [
264
294
  path.join(__dirname, '../routes/*.js'),
265
295
  path.join(__dirname, '../routes/*.ts'),
266
296
  ],
267
297
  };
268
298
 
269
- export const swaggerSpec = swaggerJsdoc(options);
299
+ export const swaggerSpec = swaggerJsdoc(swaggerOptions);
300
+
301
+ /**
302
+ * Mounts the Swagger UI at /api-docs
303
+ * @param {${isTS ? 'Express' : 'import("express").Express'}} app
304
+ */
305
+ export function setupSwagger(app${isTS ? ': Express' : ''}) {
306
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
307
+ customSiteTitle: '${projectName} API Docs',
308
+ swaggerOptions: {
309
+ persistAuthorization: true,
310
+ docExpansion: 'list',
311
+ filter: true,
312
+ },
313
+ }));
314
+
315
+ // Raw JSON spec endpoint (useful for Postman / code-gen)
316
+ app.get('/api-docs.json', (_req, res) => {
317
+ res.setHeader('Content-Type', 'application/json');
318
+ res.send(swaggerSpec);
319
+ });
320
+ }
270
321
  `;
271
322
  }
@@ -16,8 +16,10 @@ export {
16
16
  export {
17
17
  db,
18
18
  envConfig,
19
+ swaggerConfig,
19
20
  } from './config.js';
20
21
 
22
+
21
23
  export {
22
24
  routesIndex,
23
25
  healthRoute,
@@ -27,11 +27,41 @@ export default router;
27
27
 
28
28
  /** Generate src/routes/health.route.js */
29
29
  export function healthRoute(options) {
30
- const { language, database, projectName } = options;
30
+ const { language, database, projectName, swagger } = options;
31
31
  const isTS = language === 'typescript';
32
32
 
33
33
  const typeImports = isTS ? `import { Request, Response } from 'express';\n` : '';
34
34
 
35
+ const swaggerDoc = swagger
36
+ ? `/**
37
+ * @swagger
38
+ * /health:
39
+ * get:
40
+ * summary: Health check & uptime
41
+ * tags: [Health]
42
+ * responses:
43
+ * 200:
44
+ * description: Service metrics, uptime, version, and memory usage
45
+ * content:
46
+ * application/json:
47
+ * schema:
48
+ * type: object
49
+ * properties:
50
+ * status: { type: string, example: ok }
51
+ * uptime: { type: integer, example: 120 }
52
+ * version: { type: string, example: 1.0.0 }
53
+ * env: { type: string, example: development }
54
+ * timestamp: { type: string, example: "2026-01-01T00:00:00.000Z" }
55
+ */
56
+ `
57
+ : `/**
58
+ * GET /api/v1/health
59
+ *
60
+ * Returns the current health status of the API including uptime,
61
+ * version, environment, and timestamp.
62
+ */
63
+ `;
64
+
35
65
  return `${typeImports}import { Router } from 'express';
36
66
  import { readFileSync } from 'fs';
37
67
  import { fileURLToPath } from 'url';
@@ -48,13 +78,7 @@ try {
48
78
 
49
79
  const router = Router();
50
80
 
51
- /**
52
- * GET /api/v1/health
53
- *
54
- * Returns the current health status of the API including uptime,
55
- * version, environment, and timestamp.
56
- */
57
- router.get('/', (_req${isTS ? ': Request' : ''}, res${isTS ? ': Response' : ''}) => {
81
+ ${swaggerDoc}router.get('/', (_req${isTS ? ': Request' : ''}, res${isTS ? ': Response' : ''}) => {
58
82
  res.status(200).json({
59
83
  status: 'ok',
60
84
  uptime: Math.floor(process.uptime()),
@@ -74,7 +98,7 @@ export default router;
74
98
 
75
99
  /** Generate src/routes/user.route.js */
76
100
  export function userRoute(options) {
77
- const { auth, language, validation } = options;
101
+ const { auth, language, validation, swagger } = options;
78
102
  const isTS = language === 'typescript';
79
103
  const hasJwt = auth === 'jwt';
80
104
  const hasValidation = validation && validation !== 'none';
@@ -106,6 +130,85 @@ export function userRoute(options) {
106
130
  }
107
131
  }
108
132
 
133
+ const swaggerDoc = swagger
134
+ ? `/**
135
+ * @swagger
136
+ * /users:
137
+ * get:
138
+ * summary: Retrieve all users
139
+ * tags: [Users]
140
+ * responses:
141
+ * 200:
142
+ * description: List of users retrieved successfully
143
+ * post:
144
+ * summary: Create a new user
145
+ * tags: [Users]
146
+ * requestBody:
147
+ * required: true
148
+ * content:
149
+ * application/json:
150
+ * schema:
151
+ * type: object
152
+ * required: [name, email]
153
+ * properties:
154
+ * name: { type: string, example: "Alex Smith" }
155
+ * email: { type: string, example: "alex@example.com" }
156
+ * password: { type: string, example: "SecurePass123!" }
157
+ * responses:
158
+ * 201:
159
+ * description: User created
160
+ *
161
+ * /users/{id}:
162
+ * get:
163
+ * summary: Get user by ID
164
+ * tags: [Users]
165
+ * parameters:
166
+ * - in: path
167
+ * name: id
168
+ * required: true
169
+ * schema: { type: string }
170
+ * responses:
171
+ * 200:
172
+ * description: User found
173
+ * 404:
174
+ * description: User not found
175
+ * put:
176
+ * summary: Update user by ID
177
+ * tags: [Users]
178
+ * parameters:
179
+ * - in: path
180
+ * name: id
181
+ * required: true
182
+ * schema: { type: string }
183
+ * requestBody:
184
+ * required: true
185
+ * content:
186
+ * application/json:
187
+ * schema:
188
+ * type: object
189
+ * properties:
190
+ * name: { type: string }
191
+ * email: { type: string }
192
+ * responses:
193
+ * 200:
194
+ * description: User updated
195
+ * delete:
196
+ * summary: Delete user by ID
197
+ * tags: [Users]
198
+ * security:
199
+ * - bearerAuth: []
200
+ * parameters:
201
+ * - in: path
202
+ * name: id
203
+ * required: true
204
+ * schema: { type: string }
205
+ * responses:
206
+ * 200:
207
+ * description: User deleted
208
+ */
209
+ `
210
+ : '';
211
+
109
212
  return `import { Router } from 'express';
110
213
  import {
111
214
  getAllUsers,
@@ -120,7 +223,7 @@ const router = Router();
120
223
  // ─────────────────────────────────────────────────────────────────────────────
121
224
  // User Routes — /api/v1/users
122
225
  // ─────────────────────────────────────────────────────────────────────────────
123
-
226
+ ${swaggerDoc}
124
227
  router.get('/', ${guardStart}getAllUsers);
125
228
  router.post('/', ${guardStart}${validateCreate}createUser);
126
229
  router.get('/:id', ${guardStart}getUserById);
@@ -133,7 +236,7 @@ export default router;
133
236
 
134
237
  /** Generate src/routes/auth.route.js (JWT only) */
135
238
  export function authRoute(options) {
136
- const { language, validation } = options;
239
+ const { language, validation, swagger } = options;
137
240
  const isTS = language === 'typescript';
138
241
  const hasValidation = validation && validation !== 'none';
139
242
 
@@ -153,6 +256,69 @@ export function authRoute(options) {
153
256
  }
154
257
  }
155
258
 
259
+ const swaggerDoc = swagger
260
+ ? `/**
261
+ * @swagger
262
+ * /auth/register:
263
+ * post:
264
+ * summary: Register a new user account
265
+ * tags: [Auth]
266
+ * requestBody:
267
+ * required: true
268
+ * content:
269
+ * application/json:
270
+ * schema:
271
+ * type: object
272
+ * required: [name, email, password]
273
+ * properties:
274
+ * name: { type: string, example: "Jane Doe" }
275
+ * email: { type: string, example: "jane@example.com" }
276
+ * password: { type: string, example: "Secret123!" }
277
+ * responses:
278
+ * 201:
279
+ * description: Registered successfully
280
+ *
281
+ * /auth/login:
282
+ * post:
283
+ * summary: Authenticate user & get JWT tokens
284
+ * tags: [Auth]
285
+ * requestBody:
286
+ * required: true
287
+ * content:
288
+ * application/json:
289
+ * schema:
290
+ * type: object
291
+ * required: [email, password]
292
+ * properties:
293
+ * email: { type: string, example: "jane@example.com" }
294
+ * password: { type: string, example: "Secret123!" }
295
+ * responses:
296
+ * 200:
297
+ * description: Login successful
298
+ *
299
+ * /auth/logout:
300
+ * post:
301
+ * summary: Invalidate user session
302
+ * tags: [Auth]
303
+ * security:
304
+ * - bearerAuth: []
305
+ * responses:
306
+ * 200:
307
+ * description: Logged out
308
+ *
309
+ * /auth/me:
310
+ * get:
311
+ * summary: Get profile of logged-in user
312
+ * tags: [Auth]
313
+ * security:
314
+ * - bearerAuth: []
315
+ * responses:
316
+ * 200:
317
+ * description: Current user profile
318
+ */
319
+ `
320
+ : '';
321
+
156
322
  return `import { Router } from 'express';
157
323
  import {
158
324
  register,
@@ -168,7 +334,7 @@ const router = Router();
168
334
  // ─────────────────────────────────────────────────────────────────────────────
169
335
  // Auth Routes — /api/v1/auth
170
336
  // ─────────────────────────────────────────────────────────────────────────────
171
-
337
+ ${swaggerDoc}
172
338
  router.post('/register', authRateLimiter, ${validateRegister}register);
173
339
  router.post('/login', authRateLimiter, ${validateLogin}login);
174
340
  router.post('/logout', authenticate, logout);
package/src/utils/pkg.js CHANGED
@@ -117,11 +117,19 @@ export function buildPackageJson(options) {
117
117
 
118
118
  // ── API Style ──────────────────────────────────────────────────────────────
119
119
  if (apiStyle === 'graphql') {
120
- dependencies['@apollo/server'] = '^4.10.5';
121
- dependencies['graphql'] = '^16.9.0';
120
+ dependencies['@apollo/server'] = '^4.10.5';
121
+ dependencies['graphql'] = '^16.9.0';
122
122
  dependencies['@as-integrations/express4'] = '^1.0.0';
123
123
  }
124
124
 
125
+ // ── Swagger / OpenAPI ──────────────────────────────────────────────────────
126
+ if (options.swagger) {
127
+ dependencies['swagger-jsdoc'] = '^6.2.8';
128
+ dependencies['swagger-ui-express'] = '^5.0.1';
129
+ if (isTS) devDependencies['@types/swagger-ui-express'] = '^4.1.6';
130
+ }
131
+
132
+
125
133
  return {
126
134
  name: projectName,
127
135
  version: '1.0.0',