wynkjs 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  <div align="center">
4
4
 
5
- **A high-performance TypeScript framework built on Elysia with NestJS-style decorators**
5
+ **A high-performance TypeScript framework built on Elysia for Bun with NestJS-style decorators**
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/wynkjs.svg)](https://www.npmjs.com/package/wynkjs)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
10
+ [![Bun](https://img.shields.io/badge/Bun-1.0+-black.svg)](https://bun.sh/)
10
11
 
11
- _20x faster than Express, easier than NestJS_
12
+ _20x faster than Express, easier than NestJS, built for Bun_
12
13
 
13
- [Documentation](#documentation) • [Quick Start](#quick-start) • [Examples](#examples) • [Features](#features)
14
+ [Quick Start](#-quick-start) • [CLI Tools](#️-cli-tools) • [Features](#-features--examples) • [Documentation](#-documentation)
14
15
 
15
16
  </div>
16
17
 
@@ -18,9 +19,23 @@ _20x faster than Express, easier than NestJS_ ⚡
18
19
 
19
20
  ## About
20
21
 
21
- WynkJS is a modern, TypeScript-first web framework that brings NestJS-style decorators to the blazing-fast Elysia runtime. Its a lightweight NestJS alternative with familiar concepts—controllers, dependency injection, guards, pipes, interceptors, and exception filters—designed for building high‑performance REST APIs and backends on Node.js or Bun. WynkJS embraces ESM, ships first-class types, and keeps things simple so you can move fast without the bloat.
22
+ WynkJS is a modern, TypeScript-first web framework that brings NestJS-style decorators to the blazing-fast Elysia runtime built for **Bun**. It's a lightweight NestJS alternative with familiar concepts—controllers, dependency injection, guards, pipes, interceptors, and exception filters—designed for building high‑performance REST APIs and backends on **Bun**. WynkJS embraces ESM, ships first-class types, and keeps things simple so you can move fast without the bloat.
22
23
 
23
- Keywords: NestJS alternative, Elysia framework, TypeScript decorators, dependency injection (DI), guards, pipes, interceptors, exception filters, fast web framework, REST API, backend, Bun, Node.js.
24
+ **🚀 Get Started in 30 Seconds:**
25
+
26
+ ```bash
27
+ bunx create-wynkjs # Create new project
28
+ cd my-wynkjs-app # Navigate to project
29
+ bun run dev # Start server with hot reload
30
+ ```
31
+
32
+ Then generate your first API module:
33
+
34
+ ```bash
35
+ wynkjs g m product # Generate complete CRUD module
36
+ ```
37
+
38
+ Keywords: NestJS alternative, Elysia framework, Bun framework, TypeScript decorators, dependency injection (DI), guards, pipes, interceptors, exception filters, fast web framework, REST API, backend.
24
39
 
25
40
  ---
26
41
 
@@ -28,63 +43,171 @@ Keywords: NestJS alternative, Elysia framework, TypeScript decorators, dependenc
28
43
 
29
44
  WynkJS combines the **speed of Elysia** with the **elegant decorator syntax of NestJS**, giving you the best of both worlds:
30
45
 
31
- - 🚀 **20x Faster** - Built on Elysia, one of the fastest web frameworks
46
+ - 🚀 **20x Faster** - Built on Elysia, one of the fastest web frameworks for Bun
32
47
  - 🎨 **Decorator-Based** - Familiar NestJS-style decorators
33
48
  - 💉 **Dependency Injection** - Built-in DI (no need to import reflect-metadata!)
34
- - 🔒 **Type-Safe** - Full TypeScript support
49
+ - 🔒 **TypeScript First** - TypeScript is mandatory, not optional. Full type safety and IntelliSense support
35
50
  - 🎯 **Simple & Clean** - Easy to learn, powerful to use
36
51
  - 🔌 **Middleware Support** - Guards, interceptors, pipes, filters
37
- - ⚡ **Hot Reload** - Fast development with Bun
52
+ - ⚡ **Bun Only** - Built exclusively for Bun runtime (not Node.js)
38
53
  - 📦 **Single Import** - Everything from `wynkjs` (Injectable, Controller, Get, etc.)
39
54
 
40
55
  ---
41
56
 
42
57
  ## 📦 Installation
43
58
 
59
+ **Requirements:** Bun 1.0 or higher
60
+
61
+ ### Quick Start (Recommended)
62
+
63
+ Create a new WynkJS project with all best practices:
64
+
44
65
  ```bash
45
- npm install wynkjs elysia
66
+ bunx create-wynkjs
67
+ # or
68
+ npx create-wynkjs
46
69
  ```
47
70
 
48
- Or with Bun:
71
+ This will scaffold a complete **TypeScript** project with:
72
+
73
+ - ✅ TypeScript (strict mode, decorators enabled)
74
+ - ✅ ESLint + Prettier (optional)
75
+ - ✅ Hot reload with `bun --watch`
76
+ - ✅ Example code (controllers, services, DTOs)
77
+ - ✅ Git hooks (optional)
78
+
79
+ ### Manual Installation
80
+
81
+ Add to an existing project:
49
82
 
50
83
  ```bash
51
84
  bun add wynkjs elysia
52
85
  ```
53
86
 
87
+ **Note**: WynkJS is built specifically for **Bun**. It leverages Elysia's performance optimizations that are designed for Bun runtime. ✨
88
+
54
89
  ---
55
90
 
56
91
  ## 🚀 Quick Start
57
92
 
58
- ### 1. Create Your First Controller
93
+ ### 1. Create Your DTOs (Data Transfer Objects)
59
94
 
60
95
  ```typescript
61
- import { Controller, Get, Post, Body, Param, Injectable } from "wynkjs";
96
+ // user.dto.ts
97
+ import { DTO, CommonDTO } from "wynkjs";
98
+
99
+ export const CreateUserDTO = DTO.Strict({
100
+ name: DTO.Optional(DTO.String({ minLength: 2, maxLength: 50 })),
101
+ email: CommonDTO.Email({
102
+ description: "User email address",
103
+ }),
104
+ mobile: DTO.Optional(
105
+ DTO.String({
106
+ pattern: "^[6-9]{1}[0-9]{9}$",
107
+ errorMessage: "Invalid mobile number",
108
+ })
109
+ ),
110
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
111
+ });
112
+
113
+ export interface CreateUserType {
114
+ name?: string;
115
+ email?: string;
116
+ mobile?: string;
117
+ age?: number;
118
+ }
119
+
120
+ export const UserIdDto = DTO.Object({
121
+ id: DTO.String({ minLength: 2, maxLength: 50 }),
122
+ });
123
+
124
+ export interface ParamIdType {
125
+ id: string;
126
+ }
127
+ ```
128
+
129
+ ### 2. Create a Service with Dependency Injection
130
+
131
+ ```typescript
132
+ // email.service.ts
133
+ import { Injectable } from "wynkjs";
134
+
135
+ @Injectable()
136
+ export class EmailService {
137
+ async sendWelcomeEmail(email: string, userName: string): Promise<void> {
138
+ console.log(`📧 Sending welcome email to ${email}`);
139
+ // Your email logic here
140
+ }
141
+ }
142
+ ```
143
+
144
+ ### 3. Create Your Controller
145
+
146
+ ```typescript
147
+ // user.controller.ts
148
+ import {
149
+ Controller,
150
+ Get,
151
+ Post,
152
+ Body,
153
+ Param,
154
+ Patch,
155
+ Query,
156
+ Injectable,
157
+ NotFoundException,
158
+ } from "wynkjs";
159
+ import { CreateUserDTO, UserIdDto } from "./user.dto";
160
+ import type { CreateUserType, ParamIdType } from "./user.dto";
161
+ import { EmailService } from "./email.service";
62
162
 
63
163
  @Injectable()
64
164
  @Controller("/users")
65
165
  export class UserController {
166
+ constructor(private emailService: EmailService) {}
167
+
66
168
  @Get("/")
67
169
  async list() {
68
170
  return { users: ["Alice", "Bob", "Charlie"] };
69
171
  }
70
172
 
71
- @Post("/")
72
- async create(@Body() body: any) {
173
+ @Post({
174
+ path: "/",
175
+ body: CreateUserDTO,
176
+ })
177
+ async create(@Body() body: CreateUserType) {
178
+ // Send welcome email using injected service
179
+ if (body.email && body.name) {
180
+ await this.emailService.sendWelcomeEmail(body.email, body.name);
181
+ }
182
+
73
183
  return { message: "User created", data: body };
74
184
  }
75
185
 
76
- @Get("/:id")
186
+ @Get({ path: "/:id", params: UserIdDto })
77
187
  async findOne(@Param("id") id: string) {
78
188
  return { user: { id, name: "Alice" } };
79
189
  }
190
+
191
+ @Patch({
192
+ path: "/:id",
193
+ params: UserIdDto,
194
+ })
195
+ async update(@Param("id") id: string, @Body() body: any) {
196
+ if (id === "nonexistent") {
197
+ throw new NotFoundException("User not found");
198
+ }
199
+
200
+ return { message: "User updated", id, data: body };
201
+ }
80
202
  }
81
203
  ```
82
204
 
83
- ### 2. Create Your Application
205
+ ### 4. Bootstrap Your Application
84
206
 
85
207
  ```typescript
208
+ // index.ts
86
209
  import { WynkFactory } from "wynkjs";
87
- import { UserController } from "./controllers/user.controller";
210
+ import { UserController } from "./user.controller";
88
211
 
89
212
  const app = WynkFactory.create({
90
213
  controllers: [UserController],
@@ -95,12 +218,32 @@ await app.listen(3000);
95
218
  console.log("🚀 Server running on http://localhost:3000");
96
219
  ```
97
220
 
98
- **Note**: No need to import `reflect-metadata` - WynkJS handles it automatically! ✨
99
-
100
- ### 3. Run Your Server
221
+ ### 5. Run Your Server
101
222
 
102
223
  ```bash
103
224
  bun run index.ts
225
+ # or with --watch for hot reload
226
+ bun --watch index.ts
227
+ ```
228
+
229
+ ### 6. Test Your API
230
+
231
+ ```bash
232
+ # List users
233
+ curl http://localhost:3000/users
234
+
235
+ # Create user (with validation)
236
+ curl -X POST http://localhost:3000/users \
237
+ -H "Content-Type: application/json" \
238
+ -d '{"name":"John","email":"john@example.com","age":25}'
239
+
240
+ # Get user by ID
241
+ curl http://localhost:3000/users/123
242
+
243
+ # Update user
244
+ curl -X PATCH http://localhost:3000/users/123 \
245
+ -H "Content-Type: application/json" \
246
+ -d '{"email":"newemail@example.com"}'
104
247
  ```
105
248
 
106
249
  That's it! 🎉
@@ -152,6 +295,159 @@ That's it! 🎉
152
295
 
153
296
  ---
154
297
 
298
+ ## 🛠️ CLI Tools
299
+
300
+ WynkJS provides powerful CLI tools to speed up your development workflow:
301
+
302
+ ### 📦 create-wynkjs - Project Scaffolding
303
+
304
+ Quickly scaffold a new WynkJS project with best practices:
305
+
306
+ ```bash
307
+ # Create a new project
308
+ bunx create-wynkjs
309
+ # or
310
+ npx create-wynkjs
311
+ ```
312
+
313
+ **What you get:**
314
+
315
+ - ✅ **TypeScript** - Strict mode with decorators enabled (mandatory)
316
+ - ✅ **ESLint** - Code linting with TypeScript rules (optional)
317
+ - ✅ **Prettier** - Code formatting (optional)
318
+ - ✅ **Husky** - Git hooks for pre-commit checks (optional)
319
+ - ✅ **Hot Reload** - `bun --watch` for instant feedback
320
+ - ✅ **Working Example** - Complete CRUD controller, service, and DTOs
321
+
322
+ **Example:**
323
+
324
+ ```bash
325
+ bunx create-wynkjs
326
+ # Choose project name: my-api
327
+ # Add ESLint? Yes
328
+ # Add Prettier? Yes
329
+ # Add Husky? No
330
+
331
+ cd my-api
332
+ bun run dev
333
+ # 🚀 Server running on http://localhost:3000
334
+ ```
335
+
336
+ ### ⚡ wynkjs-cli - Code Generator
337
+
338
+ Generate modules, controllers, services, and DTOs instantly:
339
+
340
+ ```bash
341
+ # Install globally (recommended)
342
+ bun add -g wynkjs-cli
343
+
344
+ # Or install in project
345
+ bun add -D wynkjs-cli
346
+ ```
347
+
348
+ **Commands:**
349
+
350
+ ```bash
351
+ # Generate complete CRUD module (controller + service + DTO)
352
+ wynkjs generate module product
353
+ # or short: wynkjs g m product
354
+
355
+ # Generate controller only (all HTTP methods)
356
+ wynkjs generate controller user
357
+ # or short: wynkjs g c user
358
+
359
+ # Generate service only (all CRUD methods)
360
+ wynkjs generate service order
361
+ # or short: wynkjs g s order
362
+
363
+ # Generate DTO only (Create, Update, ID DTOs)
364
+ wynkjs generate dto payment
365
+ # or short: wynkjs g d payment
366
+ ```
367
+
368
+ **What it generates:**
369
+
370
+ ```bash
371
+ wynkjs g m product
372
+ # Creates:
373
+ # src/modules/product/
374
+ # ├── product.controller.ts # Full CRUD controller
375
+ # ├── product.service.ts # All CRUD methods
376
+ # └── product.dto.ts # Validation schemas
377
+ ```
378
+
379
+ **Auto-imports:** Controllers are automatically imported and added to `src/index.ts`!
380
+
381
+ **Generated Code Example:**
382
+
383
+ ```typescript
384
+ // product.controller.ts - Ready to use!
385
+ @Injectable()
386
+ @Controller("/product")
387
+ export class ProductController {
388
+ constructor(private productService: ProductService) {}
389
+
390
+ @Get("/")
391
+ async findAll() {
392
+ /* ... */
393
+ }
394
+
395
+ @Post({ path: "/", body: CreateProductDTO })
396
+ async create(@Body() body: CreateProductType) {
397
+ /* ... */
398
+ }
399
+
400
+ @Get({ path: "/:id", params: ProductIdDto })
401
+ async findOne(@Param("id") id: string) {
402
+ /* ... */
403
+ }
404
+
405
+ @Put({ path: "/:id", params: ProductIdDto, body: UpdateProductDTO })
406
+ async update(@Param("id") id: string, @Body() body: UpdateProductType) {
407
+ /* ... */
408
+ }
409
+
410
+ @Delete({ path: "/:id", params: ProductIdDto })
411
+ async remove(@Param("id") id: string) {
412
+ /* ... */
413
+ }
414
+ }
415
+ ```
416
+
417
+ **Full Workflow:**
418
+
419
+ ```bash
420
+ # 1. Create new project
421
+ bunx create-wynkjs
422
+ cd my-api
423
+
424
+ # 2. Generate your first module
425
+ wynkjs g m product
426
+
427
+ # 3. Start developing
428
+ bun run dev
429
+
430
+ # 4. Your API is ready!
431
+ curl http://localhost:3000/product
432
+ # {"data":[]}
433
+ ```
434
+
435
+ **Custom Configuration** (optional):
436
+
437
+ Create `wynkjs.config.json` in your project root:
438
+
439
+ ```json
440
+ {
441
+ "srcDir": "src",
442
+ "controllersDir": "src/controllers",
443
+ "servicesDir": "src/services",
444
+ "dtoDir": "src/dto",
445
+ "modulesDir": "src/modules"
446
+ }
447
+ ```
448
+
449
+ ---
450
+
155
451
  ## 🎯 Features & Examples
156
452
 
157
453
  ### 🔒 Authentication with Guards
@@ -211,38 +507,52 @@ export class AdminController {
211
507
 
212
508
  ### 💉 Dependency Injection
213
509
 
510
+ WynkJS includes powerful dependency injection with **zero setup required**:
511
+
214
512
  ```typescript
215
- // Option 1: Capital-cased (recommended for consistency)
216
- import { Injectable, Inject, Controller, Get } from "wynkjs";
513
+ // email.service.ts
514
+ import { Injectable } from "wynkjs";
217
515
 
218
516
  @Injectable()
219
- export class UserService {
220
- async findAll() {
221
- return [{ id: 1, name: "Alice" }];
517
+ export class EmailService {
518
+ async sendWelcomeEmail(email: string, userName: string): Promise<void> {
519
+ console.log(`📧 Sending welcome email to ${email}`);
520
+ // Your email sending logic
521
+ }
522
+
523
+ async sendPasswordResetEmail(
524
+ email: string,
525
+ resetToken: string
526
+ ): Promise<void> {
527
+ console.log(`🔐 Sending password reset to ${email}`);
528
+ // Your reset email logic
222
529
  }
223
530
  }
224
531
 
532
+ // user.controller.ts
533
+ import { Controller, Post, Body, Injectable } from "wynkjs";
534
+ import { EmailService } from "./email.service";
535
+
225
536
  @Injectable()
226
537
  @Controller("/users")
227
538
  export class UserController {
228
- constructor(private userService: UserService) {}
539
+ // EmailService is automatically injected!
540
+ constructor(private emailService: EmailService) {}
229
541
 
230
- @Get("/")
231
- async list() {
232
- const users = await this.userService.findAll();
233
- return { users };
542
+ @Post("/")
543
+ async create(@Body() body: { name: string; email: string }) {
544
+ // Use the injected service
545
+ await this.emailService.sendWelcomeEmail(body.email, body.name);
546
+ return { message: "User created and email sent!" };
234
547
  }
235
- }
236
- ```
237
548
 
238
- ```typescript
239
- // Option 2: Lowercase (tsyringe convention)
240
- import { Injectable, Inject, Controller, Get } from "wynkjs";
241
-
242
- @Injectable()
243
- export class UserService {
244
- async findAll() {
245
- return [{ id: 1, name: "Alice" }];
549
+ @Post("/send-reset-email")
550
+ async sendPasswordReset(@Body() body: { email: string }) {
551
+ await this.emailService.sendPasswordResetEmail(
552
+ body.email,
553
+ "reset-token-123"
554
+ );
555
+ return { message: "Password reset email sent" };
246
556
  }
247
557
  }
248
558
  ```
@@ -254,15 +564,15 @@ export class UserService {
254
564
  ### 🗃️ Database Integration (Drizzle ORM)
255
565
 
256
566
  ```typescript
257
- import { drizzle } from "drizzle-orm/node-postgres";
258
- import { pgTable, varchar } from "drizzle-orm/pg-core";
567
+ import { drizzle } from "drizzle-orm/bun-sqlite";
568
+ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
259
569
  import { InjectTable, registerTables } from "wynkjs";
260
570
 
261
571
  // Define your table
262
- const userTable = pgTable("users", {
263
- id: varchar("id").primaryKey(),
264
- name: varchar("name").notNull(),
265
- email: varchar("email").notNull().unique(),
572
+ const userTable = sqliteTable("users", {
573
+ id: integer("id").primaryKey(),
574
+ name: text("name").notNull(),
575
+ email: text("email").notNull().unique(),
266
576
  });
267
577
 
268
578
  // Register tables
@@ -282,16 +592,82 @@ export class UserService {
282
592
 
283
593
  ### 📝 Request Validation
284
594
 
285
- WynkJS provides automatic request validation with customizable error formats:
595
+ WynkJS provides automatic request validation with **full IntelliSense support** and customizable error formats:
286
596
 
287
597
  ```typescript
288
- import { Post, Body, DTO, WynkFactory, FormatErrorFormatter } from "wynkjs";
598
+ // user.dto.ts
599
+ import { DTO, CommonDTO } from "wynkjs";
600
+
601
+ // ✨ Full IntelliSense when typing DTO.String(), DTO.Number(), etc!
602
+ export const CreateUserDTO = DTO.Strict({
603
+ name: DTO.Optional(DTO.String({ minLength: 2, maxLength: 50 })),
604
+ email: CommonDTO.Email({
605
+ description: "User email address",
606
+ }),
607
+ mobile: DTO.Optional(
608
+ DTO.String({
609
+ pattern: "^[6-9]{1}[0-9]{9}$",
610
+ errorMessage: "Invalid mobile number",
611
+ })
612
+ ),
613
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
614
+ });
615
+
616
+ export interface CreateUserType {
617
+ name?: string;
618
+ email?: string;
619
+ mobile?: string;
620
+ age?: number;
621
+ }
289
622
 
290
- // Define your DTO with validation rules
291
- const CreateUserDTO = DTO.Strict({
292
- name: DTO.String({ minLength: 2 }),
293
- email: DTO.String({ format: "email", minLength: 5 }),
294
- age: DTO.Number({ minimum: 18 }),
623
+ export const UserUpdateDTO = DTO.Strict({
624
+ email: DTO.Optional(DTO.String({ format: "email", minLength: 5 })),
625
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
626
+ });
627
+
628
+ export interface UserUpdateType {
629
+ email?: string;
630
+ age?: number;
631
+ }
632
+
633
+ // user.controller.ts
634
+ import { Controller, Post, Patch, Body, Param } from "wynkjs";
635
+ import { CreateUserDTO, UserUpdateDTO } from "./user.dto";
636
+ import type { CreateUserType, UserUpdateType } from "./user.dto";
637
+
638
+ @Controller("/users")
639
+ export class UserController {
640
+ @Post({
641
+ path: "/",
642
+ body: CreateUserDTO, // ✅ Automatic validation
643
+ })
644
+ async create(@Body() body: CreateUserType) {
645
+ // Body is validated automatically!
646
+ // Invalid requests get clear error messages
647
+ return { message: "User created", data: body };
648
+ }
649
+
650
+ @Patch({
651
+ path: "/:id",
652
+ body: UserUpdateDTO, // ✅ Different schema for updates
653
+ })
654
+ async update(@Param("id") id: string, @Body() body: UserUpdateType) {
655
+ return { message: "User updated", id, data: body };
656
+ }
657
+ }
658
+ ```
659
+
660
+ **Customize validation error format:**
661
+
662
+ ```typescript
663
+ import { WynkFactory, FormatErrorFormatter } from "wynkjs";
664
+
665
+ const app = WynkFactory.create({
666
+ controllers: [UserController],
667
+ // Choose your validation error format
668
+ validationErrorFormatter: new FormatErrorFormatter(), // NestJS-style (recommended)
669
+ // validationErrorFormatter: new SimpleErrorFormatter(), // Simple array
670
+ // validationErrorFormatter: new DetailedErrorFormatter(), // Detailed with paths
295
671
  });
296
672
 
297
673
  @Controller("/users")
@@ -318,7 +694,70 @@ const app = WynkFactory.create({
318
694
  });
319
695
  ```
320
696
 
321
- **See [VALIDATION_FORMATTERS.md](./docs/VALIDATION_FORMATTERS.md) for all available error formats**
697
+ **See [VALIDATION_FORMATTERS.md](./docs-wynkjs/VALIDATION_FORMATTERS.md) for all available error formats**
698
+
699
+ ### 🚫 Exception Handling
700
+
701
+ ```typescript
702
+ import { Controller, Get, Param, NotFoundException } from "wynkjs";
703
+
704
+ @Controller("/users")
705
+ export class UserController {
706
+ @Get("/:id")
707
+ async findOne(@Param("id") id: string) {
708
+ // Built-in exceptions
709
+ if (id === "nonexistent") {
710
+ throw new NotFoundException("User not found");
711
+ }
712
+
713
+ return { user: { id, name: "Alice" } };
714
+ }
715
+ }
716
+ ```
717
+
718
+ **Built-in exceptions:**
719
+
720
+ - `BadRequestException` - 400
721
+ - `UnauthorizedException` - 401
722
+ - `ForbiddenException` - 403
723
+ - `NotFoundException` - 404
724
+ - `InternalServerErrorException` - 500
725
+
726
+ ### 🔄 Multiple Params and Query Validation
727
+
728
+ ```typescript
729
+ // user.dto.ts
730
+ export const MultiParamDto = DTO.Object({
731
+ id1: DTO.String({ minLength: 2, maxLength: 50 }),
732
+ id2: DTO.String({ minLength: 2, maxLength: 50 }),
733
+ });
734
+
735
+ export const UserQueryDto = DTO.Strict({
736
+ includePosts: DTO.Optional(DTO.Boolean({ default: false })),
737
+ includeComments: DTO.Optional(DTO.Boolean({ default: false })),
738
+ });
739
+
740
+ // user.controller.ts
741
+ @Post({
742
+ path: "/:id1/:id2",
743
+ body: CreateUserDTO,
744
+ params: MultiParamDto, // ✅ Validates route params
745
+ query: UserQueryDto, // ✅ Validates query params
746
+ })
747
+ async create(
748
+ @Body() body: CreateUserType,
749
+ @Param("id1") id1: string,
750
+ @Param("id2") id2: string,
751
+ @Query() query: UserQueryType
752
+ ) {
753
+ return {
754
+ message: "User created",
755
+ data: body,
756
+ params: { id1, id2 },
757
+ query
758
+ };
759
+ }
760
+ ```
322
761
 
323
762
  ### 🔄 Multiple Middleware
324
763
 
@@ -348,217 +787,475 @@ export class ApiController {
348
787
 
349
788
  ## 🏗️ Project Structure
350
789
 
790
+ Recommended project structure for WynkJS applications:
791
+
351
792
  ```
352
793
  my-wynk-app/
353
794
  ├── src/
354
- │ ├── controllers/
355
- │ │ ├── user.controller.ts
356
- │ │ └── auth.controller.ts
357
- │ ├── services/
358
- │ │ ├── user.service.ts
359
- │ │ └── auth.service.ts
360
- │ ├── middleware/
361
- │ │ ├── jwt.guard.ts
362
- │ │ └── roles.guard.ts
363
- │ ├── dto/
364
- │ │ └── user.dto.ts
795
+ │ ├── modules/
796
+ │ │ ├── user/
797
+ │ │ │ ├── user.controller.ts
798
+ │ │ ├── user.service.ts
799
+ │ │ │ └── user.dto.ts
800
+ │ │ └── product/
801
+ ├── product.controller.ts
802
+ │ │ ├── product.service.ts
803
+ │ │ └── product.dto.ts
804
+ │ ├── exceptions/
805
+ │ │ └── custom.exceptions.ts
806
+ │ ├── guards/
807
+ │ │ └── auth.guard.ts
808
+ │ ├── filters/
809
+ │ │ └── http-exception.filter.ts
365
810
  │ └── index.ts
366
811
  ├── package.json
367
812
  └── tsconfig.json
368
813
  ```
369
814
 
815
+ **Module-based Organization:**
816
+
817
+ - Each feature/domain lives in its own module folder
818
+ - Controllers, services, and DTOs are co-located
819
+ - Easy to navigate and maintain
820
+ - Generated automatically by `wynkjs-cli`
821
+
370
822
  ---
371
823
 
372
- ## 🎨 Complete Example
824
+ ## 🎨 Complete Working Example
825
+
826
+ Here's a complete, production-ready example with all features:
373
827
 
374
828
  ```typescript
375
- // index.ts
376
- import "reflect-metadata";
377
- import { WynkFramework } from "wynkjs";
378
- import { UserController } from "./controllers/user.controller";
379
- import { AuthController } from "./controllers/auth.controller";
829
+ // dto/user.dto.ts
830
+ import { DTO, CommonDTO } from "wynkjs";
831
+
832
+ export const CreateUserDTO = DTO.Strict({
833
+ name: DTO.Optional(DTO.String({ minLength: 2, maxLength: 50 })),
834
+ email: CommonDTO.Email({ description: "User email address" }),
835
+ mobile: DTO.Optional(
836
+ DTO.String({
837
+ pattern: "^[6-9]{1}[0-9]{9}$",
838
+ errorMessage: "Invalid mobile number",
839
+ })
840
+ ),
841
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
842
+ });
380
843
 
381
- const app = await WynkFramework.create({
382
- controllers: [UserController, AuthController],
383
- globalGuards: [],
384
- globalInterceptors: [],
844
+ export const UserIdDto = DTO.Object({
845
+ id: DTO.String({ minLength: 2, maxLength: 50 }),
385
846
  });
386
847
 
387
- await app.listen(3000);
388
- console.log("🚀 Server running on http://localhost:3000");
389
- ```
848
+ export interface CreateUserType {
849
+ name?: string;
850
+ email: string;
851
+ mobile?: string;
852
+ age?: number;
853
+ }
854
+
855
+ // services/email.service.ts
856
+ import { Injectable } from "wynkjs";
857
+
858
+ @Injectable()
859
+ export class EmailService {
860
+ async sendWelcomeEmail(email: string, userName: string): Promise<void> {
861
+ console.log(`📧 Sending welcome email to ${email}`);
862
+ // Your email sending logic (SendGrid, AWS SES, etc.)
863
+ }
864
+ }
390
865
 
391
- ```typescript
392
866
  // controllers/user.controller.ts
393
867
  import {
394
- Injectable,
395
- Inject,
396
868
  Controller,
397
869
  Get,
398
870
  Post,
399
- Put,
400
- Delete,
871
+ Patch,
401
872
  Body,
402
873
  Param,
403
- Use,
874
+ Injectable,
875
+ NotFoundException,
404
876
  } from "wynkjs";
405
- import { UserService } from "../services/user.service";
406
- import { jwtGuard } from "../middleware/jwt.guard";
877
+ import { CreateUserDTO, UserIdDto } from "../dto/user.dto";
878
+ import type { CreateUserType } from "../dto/user.dto";
879
+ import { EmailService } from "../services/email.service";
407
880
 
408
881
  @Injectable()
409
882
  @Controller("/users")
410
- @Use(jwtGuard)
411
883
  export class UserController {
412
- constructor(@Inject(UserService) private userService: UserService) {}
884
+ constructor(private emailService: EmailService) {}
413
885
 
414
886
  @Get("/")
415
887
  async list() {
416
- const users = await this.userService.findAll();
417
- return { users };
888
+ return { users: ["Alice", "Bob", "Charlie"] };
418
889
  }
419
890
 
420
- @Get("/:id")
421
- async findOne(@Param("id") id: string) {
422
- const user = await this.userService.findById(id);
423
- return { user };
891
+ @Post({ path: "/", body: CreateUserDTO })
892
+ async create(@Body() body: CreateUserType) {
893
+ // Send welcome email using injected service
894
+ if (body.email && body.name) {
895
+ await this.emailService.sendWelcomeEmail(body.email, body.name);
896
+ }
897
+ return { message: "User created", data: body };
424
898
  }
425
899
 
426
- @Post("/")
427
- async create(@Body() body: any) {
428
- const user = await this.userService.create(body);
429
- return { message: "User created", user };
900
+ @Get({ path: "/:id", params: UserIdDto })
901
+ async findOne(@Param("id") id: string) {
902
+ if (id === "nonexistent") {
903
+ throw new NotFoundException("User not found");
904
+ }
905
+ return { user: { id, name: "Alice" } };
430
906
  }
431
907
 
432
- @Put("/:id")
908
+ @Patch({ path: "/:id", params: UserIdDto })
433
909
  async update(@Param("id") id: string, @Body() body: any) {
434
- const user = await this.userService.update(id, body);
435
- return { message: "User updated", user };
910
+ return { message: "User updated", id, data: body };
436
911
  }
912
+ }
437
913
 
438
- @Delete("/:id")
439
- @HttpCode(204)
440
- async delete(@Param("id") id: string) {
441
- await this.userService.delete(id);
442
- }
914
+ // index.ts
915
+ import { WynkFactory } from "wynkjs";
916
+ import { UserController } from "./controllers/user.controller";
917
+
918
+ const app = WynkFactory.create({
919
+ controllers: [UserController],
920
+ });
921
+
922
+ await app.listen(3000);
923
+ console.log("🚀 Server running on http://localhost:3000");
924
+ ```
925
+
926
+ **Test the API:**
927
+
928
+ ```bash
929
+ # List all users
930
+ curl http://localhost:3000/users
931
+
932
+ # Create a new user (with validation and email)
933
+ curl -X POST http://localhost:3000/users \
934
+ -H "Content-Type: application/json" \
935
+ -d '{"name":"Alice","email":"alice@example.com","age":25}'
936
+
937
+ # Get user by ID
938
+ curl http://localhost:3000/users/123
939
+
940
+ # Update user
941
+ curl -X PATCH http://localhost:3000/users/123 \
942
+ -H "Content-Type: application/json" \
943
+ -d '{"email":"newemail@example.com"}'
944
+
945
+ # Test 404 exception
946
+ curl http://localhost:3000/users/nonexistent
947
+ ```
948
+
949
+ ---
950
+
951
+ ## 📖 API Reference
952
+
953
+ ### Core Decorators
954
+
955
+ #### `@Controller(basePath?: string)`
956
+
957
+ Define a controller class with optional base path.
958
+
959
+ ```typescript
960
+ @Controller("/users")
961
+ export class UserController {
962
+ // All routes will be prefixed with /users
443
963
  }
444
964
  ```
445
965
 
966
+ #### `@Get(path?: string)` / `@Post()` / `@Patch()` / `@Delete()`
967
+
968
+ HTTP method decorators with optional path and options.
969
+
446
970
  ```typescript
447
- // services/user.service.ts
971
+ @Get("/") // GET /users
972
+ @Post({ path: "/", body: CreateUserDTO }) // POST with validation
973
+ @Patch({ path: "/:id", params: UserIdDto }) // PATCH with param validation
974
+ ```
448
975
 
449
- @Injectable()
450
- export class UserService {
451
- private users = [
452
- { id: "1", name: "Alice", email: "alice@example.com" },
453
- { id: "2", name: "Bob", email: "bob@example.com" },
454
- ];
976
+ #### `@Body()` / `@Param(key?)` / `@Query(key?)`
455
977
 
456
- async findAll() {
457
- return this.users;
458
- }
978
+ Parameter extraction decorators.
459
979
 
460
- async findById(id: string) {
461
- return this.users.find((u) => u.id === id);
462
- }
980
+ ```typescript
981
+ async create(
982
+ @Body() body: CreateUserType, // Full body
983
+ @Param("id") id: string, // Single param
984
+ @Query() query: UserQueryType // Full query object
985
+ ) {}
986
+ ```
463
987
 
464
- async create(data: any) {
465
- const user = { id: Date.now().toString(), ...data };
466
- this.users.push(user);
467
- return user;
468
- }
988
+ #### `@Injectable()`
469
989
 
470
- async update(id: string, data: any) {
471
- const index = this.users.findIndex((u) => u.id === id);
472
- if (index !== -1) {
473
- this.users[index] = { ...this.users[index], ...data };
474
- return this.users[index];
475
- }
476
- return null;
477
- }
990
+ Mark a class as injectable for dependency injection.
478
991
 
479
- async delete(id: string) {
480
- const index = this.users.findIndex((u) => u.id === id);
481
- if (index !== -1) {
482
- this.users.splice(index, 1);
483
- }
484
- }
992
+ ```typescript
993
+ @Injectable()
994
+ export class EmailService {
995
+ // This service can be injected into controllers
485
996
  }
486
997
  ```
487
998
 
488
- ---
999
+ ### DTO Helpers
489
1000
 
490
- ## 🔧 API Reference
1001
+ #### `DTO.Strict(properties, options?)`
491
1002
 
492
- ### WynkFramework.create(options)
1003
+ Create object schema that strips additional properties.
493
1004
 
494
- Create a new WynkJS application.
1005
+ ```typescript
1006
+ const UserDTO = DTO.Strict({
1007
+ name: DTO.String(),
1008
+ email: DTO.String({ format: "email" }),
1009
+ });
1010
+ ```
495
1011
 
496
- **Options:**
1012
+ #### `CommonDTO` Patterns
497
1013
 
498
- - `controllers: Array<Class>` - Array of controller classes
499
- - `globalGuards?: Array<Guard>` - Global guards (optional)
500
- - `globalInterceptors?: Array<Interceptor>` - Global interceptors (optional)
501
- - `globalPipes?: Array<Pipe>` - Global pipes (optional)
502
- - `globalFilters?: Array<Filter>` - Global exception filters (optional)
1014
+ Pre-built validation patterns for common use cases.
503
1015
 
504
- **Returns:** Promise<WynkFramework>
1016
+ ```typescript
1017
+ CommonDTO.Email(); // Email validation
1018
+ CommonDTO.Name(); // Name (2-50 chars)
1019
+ CommonDTO.Password(); // Password (min 6 chars)
1020
+ CommonDTO.UUID(); // UUID format
1021
+ CommonDTO.PhoneIN(); // Indian phone number
1022
+ ```
505
1023
 
506
- ### app.listen(port, callback?)
1024
+ ### Exception Classes
507
1025
 
508
- Start the server on the specified port.
1026
+ ```typescript
1027
+ throw new NotFoundException("User not found"); // 404
1028
+ throw new BadRequestException("Invalid input"); // 400
1029
+ throw new UnauthorizedException("Not authenticated"); // 401
1030
+ throw new ForbiddenException("Access denied"); // 403
1031
+ throw new InternalServerErrorException("Error"); // 500
1032
+ ```
509
1033
 
510
1034
  ---
511
1035
 
512
- ## 🎯 Performance
1036
+ ## �️ CLI Tool
513
1037
 
514
- WynkJS is built on Elysia, which is **20x faster than Express**:
1038
+ ### create-wynkjs
515
1039
 
516
- | Framework | Requests/sec | Latency (avg) |
517
- | ---------- | ------------ | ------------- |
518
- | **WynkJS** | **~250,000** | **~0.4ms** |
519
- | Elysia | ~250,000 | ~0.4ms |
520
- | Fastify | ~45,000 | ~2.2ms |
521
- | Express | ~12,000 | ~8.3ms |
1040
+ Quickly scaffold a new WynkJS project with best practices:
522
1041
 
523
- _Benchmarks may vary based on hardware and configuration_
1042
+ ```bash
1043
+ bunx create-wynkjs
1044
+ # or
1045
+ npx create-wynkjs
1046
+ ```
524
1047
 
525
- ---
1048
+ **Features:**
526
1049
 
527
- ## 🤝 Contributing
1050
+ - 🎯 Interactive project setup
1051
+ - ✅ TypeScript configuration (strict mode)
1052
+ - 🔍 ESLint with TypeScript rules
1053
+ - 💅 Prettier for code formatting
1054
+ - 🪝 Husky for Git hooks (optional)
1055
+ - 🔥 Hot reload with `bun --watch` (faster than nodemon)
1056
+ - 📝 Complete working example (CRUD API)
528
1057
 
529
- Contributions are welcome! Please feel free to submit a Pull Request.
1058
+ **Generated Project Structure:**
530
1059
 
531
- ---
1060
+ ```
1061
+ my-wynkjs-app/
1062
+ ├── src/
1063
+ │ ├── modules/
1064
+ │ │ └── user/
1065
+ │ │ ├── user.controller.ts
1066
+ │ │ ├── user.service.ts
1067
+ │ │ └── user.dto.ts
1068
+ │ └── index.ts
1069
+ ├── .eslintrc.json
1070
+ ├── .prettierrc
1071
+ ├── tsconfig.json
1072
+ └── package.json
1073
+ ```
532
1074
 
533
- ## 📄 License
1075
+ **Available Scripts:**
534
1076
 
535
- MIT © Alam Jamal
1077
+ - `bun run dev` - Development with hot reload
1078
+ - `bun run start` - Production server
1079
+ - `bun run build` - Build TypeScript
1080
+ - `bun run lint` - Run ESLint
1081
+ - `bun run format` - Format with Prettier
1082
+
1083
+ [Learn more about create-wynkjs](./packages/create-wynkjs/README.md)
536
1084
 
537
1085
  ---
538
1086
 
539
- ## 🔗 Links
1087
+ ## �🔗 Resources
540
1088
 
541
- - [GitHub Repository](https://github.com/alamjamal/wynkjs)
542
- - [Issue Tracker](https://github.com/alamjamal/wynkjs/issues)
543
- - [Elysia Documentation](https://elysiajs.com/)
544
- - [TypeScript Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
1089
+ - 📚 [Full Documentation](https://github.com/wynkjs/wynkjs-core)
1090
+ - 🚀 [CLI Tool (create-wynkjs)](./packages/create-wynkjs/README.md)
1091
+ - 🎨 [Validation Formatters](./docs-wynkjs/VALIDATION_FORMATTERS.md)
1092
+ - 📝 [Changelog](./CHANGELOG.md)
1093
+ - 🐛 [Report Issues](https://github.com/wynkjs/wynkjs-core/issues)
545
1094
 
546
1095
  ---
547
1096
 
548
- ## 💖 Acknowledgments
1097
+ ## 🤝 Contributing
1098
+
1099
+ We welcome contributions from the community! Whether you're fixing bugs, improving documentation, or proposing new features, your help is appreciated.
549
1100
 
550
- Built with:
1101
+ ### 🐛 Reporting Issues
551
1102
 
552
- - [Elysia](https://elysiajs.com/) - The fast web framework
553
- - [tsyringe](https://github.com/microsoft/tsyringe) - Dependency injection
554
- - [TypeScript](https://www.typescriptlang.org/) - Type safety
1103
+ If you find a bug or have a feature request:
555
1104
 
556
- ---
1105
+ 1. **Check existing issues** to avoid duplicates
1106
+ 2. **Create a new issue** with a clear title and description
1107
+ 3. **Provide details**: Steps to reproduce, expected behavior, actual behavior
1108
+ 4. **Include environment info**: Bun version, OS, WynkJS version
557
1109
 
558
- <div align="center">
1110
+ [Report an issue →](https://github.com/wynkjs/wynkjs-core/issues)
559
1111
 
560
- **[⬆ back to top](#-wynkjs)**
1112
+ ### 💡 Contributing Code
561
1113
 
562
- Made with ❤️ by [Alam Jamal](https://github.com/alamjamal)
1114
+ #### Getting Started
563
1115
 
564
- </div>
1116
+ 1. **Fork the repository**
1117
+
1118
+ ```bash
1119
+ # Fork on GitHub, then clone your fork
1120
+ git clone https://github.com/YOUR_USERNAME/wynkjs-core.git
1121
+ cd wynkjs-core
1122
+ ```
1123
+
1124
+ 2. **Install dependencies**
1125
+
1126
+ ```bash
1127
+ bun install
1128
+ ```
1129
+
1130
+ 3. **Build the packages**
1131
+
1132
+ ```bash
1133
+ # Build main framework
1134
+ bun run build
1135
+
1136
+ # Build CLI tools
1137
+ cd packages/create-wynkjs && bun run build
1138
+ cd ../wynkjs-cli && bun run build
1139
+ ```
1140
+
1141
+ 4. **Create a branch**
1142
+ ```bash
1143
+ git checkout -b feature/your-feature-name
1144
+ # or
1145
+ git checkout -b fix/bug-description
1146
+ ```
1147
+
1148
+ #### Development Workflow
1149
+
1150
+ 1. **Make your changes** in the appropriate package:
1151
+
1152
+ - `core/` - Core framework decorators and utilities
1153
+ - `packages/create-wynkjs/` - Project scaffolding CLI
1154
+ - `packages/wynkjs-cli/` - Code generator CLI
1155
+
1156
+ 2. **Test your changes**
1157
+
1158
+ ```bash
1159
+ # Test in the example project
1160
+ cd example
1161
+ bun run dev
1162
+
1163
+ # Test CLI generation
1164
+ cd /tmp && bunx /path/to/wynkjs-core/packages/create-wynkjs
1165
+ ```
1166
+
1167
+ 3. **Build all packages**
1168
+
1169
+ ```bash
1170
+ # From project root
1171
+ bun run build
1172
+ cd packages/create-wynkjs && bun run build
1173
+ cd ../wynkjs-cli && bun run build
1174
+ ```
1175
+
1176
+ 4. **Commit your changes**
1177
+
1178
+ ```bash
1179
+ git add .
1180
+ git commit -m "feat: add new feature"
1181
+ # or
1182
+ git commit -m "fix: resolve issue with decorators"
1183
+ ```
1184
+
1185
+ **Commit Convention:**
1186
+
1187
+ - `feat:` - New feature
1188
+ - `fix:` - Bug fix
1189
+ - `docs:` - Documentation changes
1190
+ - `refactor:` - Code refactoring
1191
+ - `test:` - Adding tests
1192
+ - `chore:` - Maintenance tasks
1193
+
1194
+ 5. **Push and create a Pull Request**
1195
+
1196
+ ```bash
1197
+ git push origin feature/your-feature-name
1198
+ ```
1199
+
1200
+ Then open a Pull Request on GitHub with:
1201
+
1202
+ - Clear description of changes
1203
+ - Link to related issues
1204
+ - Screenshots/examples if applicable
1205
+
1206
+ #### Code Style
1207
+
1208
+ - **TypeScript**: Strict mode enabled
1209
+ - **Formatting**: Use Prettier (run `bun run format` if available)
1210
+ - **Linting**: Follow ESLint rules
1211
+ - **Naming**:
1212
+ - PascalCase for classes and interfaces
1213
+ - camelCase for functions and variables
1214
+ - kebab-case for file names
1215
+
1216
+ #### Testing Guidelines
1217
+
1218
+ - Test your changes in the `example/` directory
1219
+ - Ensure existing examples still work
1220
+ - Add new examples for new features
1221
+ - Test CLI tools in a fresh directory
1222
+
1223
+ ### 📝 Documentation
1224
+
1225
+ Documentation improvements are always welcome!
1226
+
1227
+ - **README updates**: Keep examples current and clear
1228
+ - **Code comments**: Add JSDoc comments for public APIs
1229
+ - **Guides**: Create helpful guides in `docs-wynkjs/`
1230
+ - **Examples**: Add real-world usage examples
1231
+
1232
+ ### 🚀 Release Process (Maintainers)
1233
+
1234
+ 1. Update `CHANGELOG.md` with changes
1235
+ 2. Bump version in `package.json` files
1236
+ 3. Build all packages
1237
+ 4. Commit and tag the release
1238
+ 5. Publish to npm:
1239
+ ```bash
1240
+ npm publish --access public
1241
+ cd packages/create-wynkjs && npm publish --access public
1242
+ cd ../wynkjs-cli && npm publish --access public
1243
+ ```
1244
+
1245
+ ### 💬 Community
1246
+
1247
+ - **GitHub Discussions**: Ask questions and share ideas
1248
+ - **Discord**: (Coming soon) Join our community chat
1249
+ - **Twitter**: Follow [@wynkjs](https://twitter.com/wynkjs) for updates
1250
+
1251
+ ### 📜 License
1252
+
1253
+ By contributing, you agree that your contributions will be licensed under the MIT License.
1254
+
1255
+ ---
1256
+
1257
+ **Thank you for contributing to WynkJS! 🎉**
1258
+
1259
+ ```
1260
+
1261
+ ```