create-wabck 1.0.0 → 1.1.1

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,601 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // Swagger / OpenAPI Templates — src/config/swagger.js/ts & openapi.yaml
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+
5
+ /** Generate src/config/swagger.js or src/config/swagger.ts */
6
+ export function swaggerConfig(options) {
7
+ const { projectName, language, auth } = options;
8
+ const isTS = language === 'typescript';
9
+ const hasJwt = auth === 'jwt';
10
+
11
+ return `import swaggerJsdoc from 'swagger-jsdoc';
12
+ import swaggerUi from 'swagger-ui-express';
13
+ import { readFileSync, existsSync } from 'fs';
14
+ import { fileURLToPath } from 'url';
15
+ import path from 'path';
16
+ ${isTS ? `import type { Express } from 'express';\n` : ''}
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+ // Production Swagger / OpenAPI 3.0 Specification
22
+ // ─────────────────────────────────────────────────────────────────────────────
23
+
24
+ // Dynamically read version from package.json
25
+ let version = '1.0.0';
26
+ try {
27
+ const pkgPath = path.resolve(__dirname, '../../package.json');
28
+ if (existsSync(pkgPath)) {
29
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
30
+ version = pkg.version || '1.0.0';
31
+ }
32
+ } catch { /* use fallback version */ }
33
+
34
+ const swaggerDefinition = {
35
+ openapi: '3.0.3',
36
+ info: {
37
+ title: '${projectName} API',
38
+ version,
39
+ description: 'Production-ready REST API documentation with interactive Swagger UI and OpenAPI 3.0 specification.',
40
+ license: {
41
+ name: 'MIT',
42
+ url: 'https://opensource.org/licenses/MIT',
43
+ },
44
+ contact: {
45
+ name: '${projectName} Team',
46
+ },
47
+ },
48
+ servers: [
49
+ {
50
+ url: \`http://localhost:\${process.env.PORT || 5000}/api/v1\`,
51
+ description: 'Local development server',
52
+ },
53
+ {
54
+ url: '/api/v1',
55
+ description: 'Current host / Reverse proxy relative path',
56
+ },
57
+ ],
58
+ tags: [
59
+ { name: 'Health', description: 'System health & diagnostic endpoints' },
60
+ { name: 'Users', description: 'User management and CRUD operations' },
61
+ ${hasJwt ? " { name: 'Auth', description: 'Authentication, sessions, and token issuance' },\n" : ''} ],
62
+ components: {
63
+ securitySchemes: {
64
+ bearerAuth: {
65
+ type: 'http',
66
+ scheme: 'bearer',
67
+ bearerFormat: 'JWT',
68
+ description: 'Provide your Bearer token in the format: \`Bearer <token>\`',
69
+ },
70
+ },
71
+ schemas: {
72
+ ApiResponse: {
73
+ type: 'object',
74
+ properties: {
75
+ success: { type: 'boolean', example: true },
76
+ statusCode: { type: 'integer', example: 200 },
77
+ message: { type: 'string', example: 'Success' },
78
+ data: { type: 'object' },
79
+ },
80
+ },
81
+ ApiError: {
82
+ type: 'object',
83
+ properties: {
84
+ success: { type: 'boolean', example: false },
85
+ statusCode: { type: 'integer', example: 400 },
86
+ message: { type: 'string', example: 'Validation or operation error' },
87
+ errors: { type: 'array', items: { type: 'string' } },
88
+ },
89
+ },
90
+ User: {
91
+ type: 'object',
92
+ properties: {
93
+ _id: { type: 'string', example: '661fae4e5bc24a1b8c9d0123' },
94
+ name: { type: 'string', example: 'Alex Mercer' },
95
+ email: { type: 'string', format: 'email', example: 'alex@example.com' },
96
+ role: { type: 'string', enum: ['user', 'admin'], example: 'user' },
97
+ isActive: { type: 'boolean', example: true },
98
+ createdAt: { type: 'string', format: 'date-time' },
99
+ updatedAt: { type: 'string', format: 'date-time' },
100
+ },
101
+ },
102
+ },
103
+ },
104
+ security: [
105
+ { bearerAuth: [] },
106
+ ],
107
+ };
108
+
109
+ const swaggerOptions = {
110
+ definition: swaggerDefinition,
111
+ apis: [
112
+ path.join(__dirname, '../routes/*.js'),
113
+ path.join(__dirname, '../routes/*.ts'),
114
+ ],
115
+ };
116
+
117
+ export const swaggerSpec = swaggerJsdoc(swaggerOptions);
118
+
119
+ /**
120
+ * Configure and mount Swagger UI and OpenAPI endpoints on the Express application.
121
+ * @param {${isTS ? 'Express' : 'import("express").Express'}} app
122
+ */
123
+ export function setupSwagger(app${isTS ? ': Express' : ''}) {
124
+ // Custom dark-accent styling for modern presentation
125
+ const customCss = \`
126
+ .swagger-ui .topbar { display: none }
127
+ .swagger-ui .info { margin: 25px 0 }
128
+ .swagger-ui .info .title { font-family: system-ui, sans-serif; font-weight: 700 }
129
+ .swagger-ui .scheme-container { background: #f8fafc; padding: 15px; border-radius: 8px; margin-bottom: 20px }
130
+ \`;
131
+
132
+ // Interactive Swagger UI
133
+ app.use(
134
+ '/api-docs',
135
+ swaggerUi.serve,
136
+ swaggerUi.setup(swaggerSpec, {
137
+ customSiteTitle: '${projectName} API Documentation',
138
+ customCss,
139
+ swaggerOptions: {
140
+ persistAuthorization: true,
141
+ docExpansion: 'list',
142
+ filter: true,
143
+ tryItOutEnabled: true,
144
+ displayRequestDuration: true,
145
+ },
146
+ })
147
+ );
148
+
149
+ // Raw OpenAPI 3.0 JSON specification (for Postman, Insomnia, or code generators)
150
+ app.get('/api-docs.json', (_req, res) => {
151
+ res.setHeader('Content-Type', 'application/json');
152
+ res.send(swaggerSpec);
153
+ });
154
+
155
+ // Raw OpenAPI 3.0 YAML specification file
156
+ app.get('/api-docs.yaml', (_req, res) => {
157
+ const yamlPath = path.resolve(__dirname, '../../openapi.yaml');
158
+ if (existsSync(yamlPath)) {
159
+ res.setHeader('Content-Type', 'text/yaml; charset=utf-8');
160
+ return res.sendFile(yamlPath);
161
+ }
162
+ // Fallback: send JSON representation if yaml file is relocated
163
+ res.setHeader('Content-Type', 'application/json');
164
+ res.send(swaggerSpec);
165
+ });
166
+ }
167
+ `;
168
+ }
169
+
170
+ /** Generate openapi.yaml for the root directory of the scaffolded project */
171
+ export function swaggerYaml(options) {
172
+ const { projectName, auth } = options;
173
+ const hasJwt = auth === 'jwt';
174
+
175
+ return `openapi: 3.0.3
176
+ info:
177
+ title: ${projectName} API
178
+ description: Production-grade REST API specification for ${projectName}. Auto-generated by wabck.
179
+ version: 1.0.0
180
+ license:
181
+ name: MIT
182
+ url: https://opensource.org/licenses/MIT
183
+ contact:
184
+ name: ${projectName} Team
185
+
186
+ servers:
187
+ - url: http://localhost:5000/api/v1
188
+ description: Local development server
189
+ - url: /api/v1
190
+ description: Current host / Reverse proxy relative path
191
+
192
+ tags:
193
+ - name: Health
194
+ description: System health & diagnostic endpoints
195
+ - name: Users
196
+ description: User management and CRUD operations
197
+ ${hasJwt ? ` - name: Auth
198
+ description: Authentication, sessions, and token issuance
199
+ ` : ''}
200
+ paths:
201
+ /health:
202
+ get:
203
+ tags:
204
+ - Health
205
+ summary: Health check & server diagnostics
206
+ description: Returns service uptime, memory metrics, runtime environment, and current version.
207
+ responses:
208
+ '200':
209
+ description: Service is healthy and responding
210
+ content:
211
+ application/json:
212
+ schema:
213
+ type: object
214
+ properties:
215
+ status:
216
+ type: string
217
+ example: ok
218
+ uptime:
219
+ type: integer
220
+ example: 120
221
+ version:
222
+ type: string
223
+ example: 1.0.0
224
+ env:
225
+ type: string
226
+ example: development
227
+ timestamp:
228
+ type: string
229
+ format: date-time
230
+ example: '2026-01-01T00:00:00.000Z'
231
+ memory:
232
+ type: object
233
+ properties:
234
+ used:
235
+ type: string
236
+ example: 32 MB
237
+ total:
238
+ type: string
239
+ example: 64 MB
240
+
241
+ /users:
242
+ get:
243
+ tags:
244
+ - Users
245
+ summary: Retrieve all users
246
+ description: Fetches a list of registered users.
247
+ responses:
248
+ '200':
249
+ description: Users retrieved successfully
250
+ content:
251
+ application/json:
252
+ schema:
253
+ type: object
254
+ properties:
255
+ success:
256
+ type: boolean
257
+ example: true
258
+ data:
259
+ type: array
260
+ items:
261
+ $ref: '#/components/schemas/User'
262
+ post:
263
+ tags:
264
+ - Users
265
+ summary: Create a new user
266
+ description: Adds a new user record to the database.
267
+ requestBody:
268
+ required: true
269
+ content:
270
+ application/json:
271
+ schema:
272
+ $ref: '#/components/schemas/CreateUserInput'
273
+ responses:
274
+ '201':
275
+ description: User created successfully
276
+ content:
277
+ application/json:
278
+ schema:
279
+ $ref: '#/components/schemas/ApiResponse'
280
+ '400':
281
+ description: Bad request or validation failure
282
+ content:
283
+ application/json:
284
+ schema:
285
+ $ref: '#/components/schemas/ApiError'
286
+
287
+ /users/{id}:
288
+ get:
289
+ tags:
290
+ - Users
291
+ summary: Get user by ID
292
+ parameters:
293
+ - name: id
294
+ in: path
295
+ required: true
296
+ description: Unique identifier of the user
297
+ schema:
298
+ type: string
299
+ responses:
300
+ '200':
301
+ description: User found
302
+ content:
303
+ application/json:
304
+ schema:
305
+ $ref: '#/components/schemas/ApiResponse'
306
+ '404':
307
+ description: User not found
308
+ content:
309
+ application/json:
310
+ schema:
311
+ $ref: '#/components/schemas/ApiError'
312
+ put:
313
+ tags:
314
+ - Users
315
+ summary: Update an existing user
316
+ parameters:
317
+ - name: id
318
+ in: path
319
+ required: true
320
+ description: Unique identifier of the user
321
+ schema:
322
+ type: string
323
+ requestBody:
324
+ required: true
325
+ content:
326
+ application/json:
327
+ schema:
328
+ $ref: '#/components/schemas/UpdateUserInput'
329
+ responses:
330
+ '200':
331
+ description: User updated successfully
332
+ content:
333
+ application/json:
334
+ schema:
335
+ $ref: '#/components/schemas/ApiResponse'
336
+ '404':
337
+ description: User not found
338
+ delete:
339
+ tags:
340
+ - Users
341
+ summary: Delete a user by ID
342
+ security:
343
+ - bearerAuth: []
344
+ parameters:
345
+ - name: id
346
+ in: path
347
+ required: true
348
+ description: Unique identifier of the user
349
+ schema:
350
+ type: string
351
+ responses:
352
+ '200':
353
+ description: User deleted successfully
354
+ content:
355
+ application/json:
356
+ schema:
357
+ $ref: '#/components/schemas/ApiResponse'
358
+ '404':
359
+ description: User not found
360
+ ${hasJwt ? `
361
+ /auth/register:
362
+ post:
363
+ tags:
364
+ - Auth
365
+ summary: Register a new account
366
+ description: Creates a new user profile and returns access tokens.
367
+ requestBody:
368
+ required: true
369
+ content:
370
+ application/json:
371
+ schema:
372
+ $ref: '#/components/schemas/RegisterInput'
373
+ responses:
374
+ '201':
375
+ description: User successfully registered
376
+ content:
377
+ application/json:
378
+ schema:
379
+ $ref: '#/components/schemas/AuthResponse'
380
+ '400':
381
+ description: Validation error or email already in use
382
+ content:
383
+ application/json:
384
+ schema:
385
+ $ref: '#/components/schemas/ApiError'
386
+
387
+ /auth/login:
388
+ post:
389
+ tags:
390
+ - Auth
391
+ summary: Authenticate user & issue tokens
392
+ description: Validates email and password, issuing access & refresh tokens.
393
+ requestBody:
394
+ required: true
395
+ content:
396
+ application/json:
397
+ schema:
398
+ $ref: '#/components/schemas/LoginInput'
399
+ responses:
400
+ '200':
401
+ description: Login successful
402
+ content:
403
+ application/json:
404
+ schema:
405
+ $ref: '#/components/schemas/AuthResponse'
406
+ '401':
407
+ description: Invalid credentials
408
+ content:
409
+ application/json:
410
+ schema:
411
+ $ref: '#/components/schemas/ApiError'
412
+
413
+ /auth/logout:
414
+ post:
415
+ tags:
416
+ - Auth
417
+ summary: Invalidate user session
418
+ security:
419
+ - bearerAuth: []
420
+ responses:
421
+ '200':
422
+ description: Logged out successfully
423
+ content:
424
+ application/json:
425
+ schema:
426
+ $ref: '#/components/schemas/ApiResponse'
427
+
428
+ /auth/me:
429
+ get:
430
+ tags:
431
+ - Auth
432
+ summary: Retrieve current authenticated user profile
433
+ security:
434
+ - bearerAuth: []
435
+ responses:
436
+ '200':
437
+ description: Profile retrieved successfully
438
+ content:
439
+ application/json:
440
+ schema:
441
+ $ref: '#/components/schemas/ApiResponse'
442
+ '401':
443
+ description: Unauthorized
444
+ ` : ''}
445
+ components:
446
+ securitySchemes:
447
+ bearerAuth:
448
+ type: http
449
+ scheme: bearer
450
+ bearerFormat: JWT
451
+ description: Supply your JSON Web Token as 'Bearer <token>'
452
+
453
+ schemas:
454
+ ApiResponse:
455
+ type: object
456
+ properties:
457
+ success:
458
+ type: boolean
459
+ example: true
460
+ statusCode:
461
+ type: integer
462
+ example: 200
463
+ message:
464
+ type: string
465
+ example: Success
466
+ data:
467
+ type: object
468
+
469
+ ApiError:
470
+ type: object
471
+ properties:
472
+ success:
473
+ type: boolean
474
+ example: false
475
+ statusCode:
476
+ type: integer
477
+ example: 400
478
+ message:
479
+ type: string
480
+ example: Error occurred
481
+ errors:
482
+ type: array
483
+ items:
484
+ type: string
485
+
486
+ User:
487
+ type: object
488
+ properties:
489
+ _id:
490
+ type: string
491
+ example: 661fae4e5bc24a1b8c9d0123
492
+ name:
493
+ type: string
494
+ example: Alex Mercer
495
+ email:
496
+ type: string
497
+ format: email
498
+ example: alex@example.com
499
+ role:
500
+ type: string
501
+ enum: [user, admin]
502
+ example: user
503
+ isActive:
504
+ type: boolean
505
+ example: true
506
+ createdAt:
507
+ type: string
508
+ format: date-time
509
+ updatedAt:
510
+ type: string
511
+ format: date-time
512
+
513
+ CreateUserInput:
514
+ type: object
515
+ required:
516
+ - name
517
+ - email
518
+ - password
519
+ properties:
520
+ name:
521
+ type: string
522
+ example: Alex Mercer
523
+ email:
524
+ type: string
525
+ format: email
526
+ example: alex@example.com
527
+ password:
528
+ type: string
529
+ format: password
530
+ example: SecurePass123!
531
+
532
+ UpdateUserInput:
533
+ type: object
534
+ properties:
535
+ name:
536
+ type: string
537
+ example: Alex Mercer
538
+ email:
539
+ type: string
540
+ format: email
541
+ example: alex@example.com
542
+
543
+ RegisterInput:
544
+ type: object
545
+ required:
546
+ - name
547
+ - email
548
+ - password
549
+ properties:
550
+ name:
551
+ type: string
552
+ example: Jane Doe
553
+ email:
554
+ type: string
555
+ format: email
556
+ example: jane@example.com
557
+ password:
558
+ type: string
559
+ format: password
560
+ example: SecretPass123!
561
+
562
+ LoginInput:
563
+ type: object
564
+ required:
565
+ - email
566
+ - password
567
+ properties:
568
+ email:
569
+ type: string
570
+ format: email
571
+ example: jane@example.com
572
+ password:
573
+ type: string
574
+ format: password
575
+ example: SecretPass123!
576
+
577
+ AuthResponse:
578
+ type: object
579
+ properties:
580
+ success:
581
+ type: boolean
582
+ example: true
583
+ statusCode:
584
+ type: integer
585
+ example: 200
586
+ message:
587
+ type: string
588
+ example: Authenticated
589
+ data:
590
+ type: object
591
+ properties:
592
+ user:
593
+ $ref: '#/components/schemas/User'
594
+ accessToken:
595
+ type: string
596
+ example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
597
+ refreshToken:
598
+ type: string
599
+ example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
600
+ `;
601
+ }
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',