wynkjs 1.0.1 → 1.0.2

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,162 @@ 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
+ # ├── controllers/
375
+ # │ └── product.controller.ts # Full CRUD controller
376
+ # ├── services/
377
+ # │ └── product.service.ts # All CRUD methods
378
+ # └── dto/
379
+ # └── product.dto.ts # Validation schemas
380
+ ```
381
+
382
+ **Auto-imports:** Controllers are automatically imported and added to `src/index.ts`!
383
+
384
+ **Generated Code Example:**
385
+
386
+ ```typescript
387
+ // product.controller.ts - Ready to use!
388
+ @Injectable()
389
+ @Controller("/product")
390
+ export class ProductController {
391
+ constructor(private productService: ProductService) {}
392
+
393
+ @Get("/")
394
+ async findAll() {
395
+ /* ... */
396
+ }
397
+
398
+ @Post({ path: "/", body: CreateProductDTO })
399
+ async create(@Body() body: CreateProductType) {
400
+ /* ... */
401
+ }
402
+
403
+ @Get({ path: "/:id", params: ProductIdDto })
404
+ async findOne(@Param("id") id: string) {
405
+ /* ... */
406
+ }
407
+
408
+ @Put({ path: "/:id", params: ProductIdDto, body: UpdateProductDTO })
409
+ async update(@Param("id") id: string, @Body() body: UpdateProductType) {
410
+ /* ... */
411
+ }
412
+
413
+ @Delete({ path: "/:id", params: ProductIdDto })
414
+ async remove(@Param("id") id: string) {
415
+ /* ... */
416
+ }
417
+ }
418
+ ```
419
+
420
+ **Full Workflow:**
421
+
422
+ ```bash
423
+ # 1. Create new project
424
+ bunx create-wynkjs
425
+ cd my-api
426
+
427
+ # 2. Generate your first module
428
+ wynkjs g m product
429
+
430
+ # 3. Start developing
431
+ bun run dev
432
+
433
+ # 4. Your API is ready!
434
+ curl http://localhost:3000/product
435
+ # {"data":[]}
436
+ ```
437
+
438
+ **Custom Configuration** (optional):
439
+
440
+ Create `wynkjs.config.json` in your project root:
441
+
442
+ ```json
443
+ {
444
+ "srcDir": "src",
445
+ "controllersDir": "src/controllers",
446
+ "servicesDir": "src/services",
447
+ "dtoDir": "src/dto",
448
+ "modulesDir": "src/modules"
449
+ }
450
+ ```
451
+
452
+ ---
453
+
155
454
  ## 🎯 Features & Examples
156
455
 
157
456
  ### 🔒 Authentication with Guards
@@ -211,38 +510,52 @@ export class AdminController {
211
510
 
212
511
  ### 💉 Dependency Injection
213
512
 
513
+ WynkJS includes powerful dependency injection with **zero setup required**:
514
+
214
515
  ```typescript
215
- // Option 1: Capital-cased (recommended for consistency)
216
- import { Injectable, Inject, Controller, Get } from "wynkjs";
516
+ // email.service.ts
517
+ import { Injectable } from "wynkjs";
217
518
 
218
519
  @Injectable()
219
- export class UserService {
220
- async findAll() {
221
- return [{ id: 1, name: "Alice" }];
520
+ export class EmailService {
521
+ async sendWelcomeEmail(email: string, userName: string): Promise<void> {
522
+ console.log(`📧 Sending welcome email to ${email}`);
523
+ // Your email sending logic
524
+ }
525
+
526
+ async sendPasswordResetEmail(
527
+ email: string,
528
+ resetToken: string
529
+ ): Promise<void> {
530
+ console.log(`🔐 Sending password reset to ${email}`);
531
+ // Your reset email logic
222
532
  }
223
533
  }
224
534
 
535
+ // user.controller.ts
536
+ import { Controller, Post, Body, Injectable } from "wynkjs";
537
+ import { EmailService } from "./email.service";
538
+
225
539
  @Injectable()
226
540
  @Controller("/users")
227
541
  export class UserController {
228
- constructor(private userService: UserService) {}
542
+ // EmailService is automatically injected!
543
+ constructor(private emailService: EmailService) {}
229
544
 
230
- @Get("/")
231
- async list() {
232
- const users = await this.userService.findAll();
233
- return { users };
545
+ @Post("/")
546
+ async create(@Body() body: { name: string; email: string }) {
547
+ // Use the injected service
548
+ await this.emailService.sendWelcomeEmail(body.email, body.name);
549
+ return { message: "User created and email sent!" };
234
550
  }
235
- }
236
- ```
237
551
 
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" }];
552
+ @Post("/send-reset-email")
553
+ async sendPasswordReset(@Body() body: { email: string }) {
554
+ await this.emailService.sendPasswordResetEmail(
555
+ body.email,
556
+ "reset-token-123"
557
+ );
558
+ return { message: "Password reset email sent" };
246
559
  }
247
560
  }
248
561
  ```
@@ -254,15 +567,15 @@ export class UserService {
254
567
  ### 🗃️ Database Integration (Drizzle ORM)
255
568
 
256
569
  ```typescript
257
- import { drizzle } from "drizzle-orm/node-postgres";
258
- import { pgTable, varchar } from "drizzle-orm/pg-core";
570
+ import { drizzle } from "drizzle-orm/bun-sqlite";
571
+ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
259
572
  import { InjectTable, registerTables } from "wynkjs";
260
573
 
261
574
  // Define your table
262
- const userTable = pgTable("users", {
263
- id: varchar("id").primaryKey(),
264
- name: varchar("name").notNull(),
265
- email: varchar("email").notNull().unique(),
575
+ const userTable = sqliteTable("users", {
576
+ id: integer("id").primaryKey(),
577
+ name: text("name").notNull(),
578
+ email: text("email").notNull().unique(),
266
579
  });
267
580
 
268
581
  // Register tables
@@ -282,16 +595,84 @@ export class UserService {
282
595
 
283
596
  ### 📝 Request Validation
284
597
 
285
- WynkJS provides automatic request validation with customizable error formats:
598
+ WynkJS provides automatic request validation with **full IntelliSense support** and customizable error formats:
599
+
600
+ > 💡 **New in v1.0.2**: Type `DTO.` and get full autocomplete! See [INTELLISENSE_GUIDE.md](./docs/INTELLISENSE_GUIDE.md)
286
601
 
287
602
  ```typescript
288
- import { Post, Body, DTO, WynkFactory, FormatErrorFormatter } from "wynkjs";
603
+ // user.dto.ts
604
+ import { DTO, CommonDTO } from "wynkjs";
605
+
606
+ // ✨ Full IntelliSense when typing DTO.String(), DTO.Number(), etc!
607
+ export const CreateUserDTO = DTO.Strict({
608
+ name: DTO.Optional(DTO.String({ minLength: 2, maxLength: 50 })),
609
+ email: CommonDTO.Email({
610
+ description: "User email address",
611
+ }),
612
+ mobile: DTO.Optional(
613
+ DTO.String({
614
+ pattern: "^[6-9]{1}[0-9]{9}$",
615
+ errorMessage: "Invalid mobile number",
616
+ })
617
+ ),
618
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
619
+ });
289
620
 
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 }),
621
+ export interface CreateUserType {
622
+ name?: string;
623
+ email?: string;
624
+ mobile?: string;
625
+ age?: number;
626
+ }
627
+
628
+ export const UserUpdateDTO = DTO.Strict({
629
+ email: DTO.Optional(DTO.String({ format: "email", minLength: 5 })),
630
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
631
+ });
632
+
633
+ export interface UserUpdateType {
634
+ email?: string;
635
+ age?: number;
636
+ }
637
+
638
+ // user.controller.ts
639
+ import { Controller, Post, Patch, Body, Param } from "wynkjs";
640
+ import { CreateUserDTO, UserUpdateDTO } from "./user.dto";
641
+ import type { CreateUserType, UserUpdateType } from "./user.dto";
642
+
643
+ @Controller("/users")
644
+ export class UserController {
645
+ @Post({
646
+ path: "/",
647
+ body: CreateUserDTO, // ✅ Automatic validation
648
+ })
649
+ async create(@Body() body: CreateUserType) {
650
+ // Body is validated automatically!
651
+ // Invalid requests get clear error messages
652
+ return { message: "User created", data: body };
653
+ }
654
+
655
+ @Patch({
656
+ path: "/:id",
657
+ body: UserUpdateDTO, // ✅ Different schema for updates
658
+ })
659
+ async update(@Param("id") id: string, @Body() body: UserUpdateType) {
660
+ return { message: "User updated", id, data: body };
661
+ }
662
+ }
663
+ ```
664
+
665
+ **Customize validation error format:**
666
+
667
+ ```typescript
668
+ import { WynkFactory, FormatErrorFormatter } from "wynkjs";
669
+
670
+ const app = WynkFactory.create({
671
+ controllers: [UserController],
672
+ // Choose your validation error format
673
+ validationErrorFormatter: new FormatErrorFormatter(), // NestJS-style (recommended)
674
+ // validationErrorFormatter: new SimpleErrorFormatter(), // Simple array
675
+ // validationErrorFormatter: new DetailedErrorFormatter(), // Detailed with paths
295
676
  });
296
677
 
297
678
  @Controller("/users")
@@ -318,7 +699,70 @@ const app = WynkFactory.create({
318
699
  });
319
700
  ```
320
701
 
321
- **See [VALIDATION_FORMATTERS.md](./docs/VALIDATION_FORMATTERS.md) for all available error formats**
702
+ **See [VALIDATION_FORMATTERS.md](./VALIDATION_FORMATTERS.md) for all available error formats**
703
+
704
+ ### 🚫 Exception Handling
705
+
706
+ ```typescript
707
+ import { Controller, Get, Param, NotFoundException } from "wynkjs";
708
+
709
+ @Controller("/users")
710
+ export class UserController {
711
+ @Get("/:id")
712
+ async findOne(@Param("id") id: string) {
713
+ // Built-in exceptions
714
+ if (id === "nonexistent") {
715
+ throw new NotFoundException("User not found");
716
+ }
717
+
718
+ return { user: { id, name: "Alice" } };
719
+ }
720
+ }
721
+ ```
722
+
723
+ **Built-in exceptions:**
724
+
725
+ - `BadRequestException` - 400
726
+ - `UnauthorizedException` - 401
727
+ - `ForbiddenException` - 403
728
+ - `NotFoundException` - 404
729
+ - `InternalServerErrorException` - 500
730
+
731
+ ### 🔄 Multiple Params and Query Validation
732
+
733
+ ```typescript
734
+ // user.dto.ts
735
+ export const MultiParamDto = DTO.Object({
736
+ id1: DTO.String({ minLength: 2, maxLength: 50 }),
737
+ id2: DTO.String({ minLength: 2, maxLength: 50 }),
738
+ });
739
+
740
+ export const UserQueryDto = DTO.Strict({
741
+ includePosts: DTO.Optional(DTO.Boolean({ default: false })),
742
+ includeComments: DTO.Optional(DTO.Boolean({ default: false })),
743
+ });
744
+
745
+ // user.controller.ts
746
+ @Post({
747
+ path: "/:id1/:id2",
748
+ body: CreateUserDTO,
749
+ params: MultiParamDto, // ✅ Validates route params
750
+ query: UserQueryDto, // ✅ Validates query params
751
+ })
752
+ async create(
753
+ @Body() body: CreateUserType,
754
+ @Param("id1") id1: string,
755
+ @Param("id2") id2: string,
756
+ @Query() query: UserQueryType
757
+ ) {
758
+ return {
759
+ message: "User created",
760
+ data: body,
761
+ params: { id1, id2 },
762
+ query
763
+ };
764
+ }
765
+ ```
322
766
 
323
767
  ### 🔄 Multiple Middleware
324
768
 
@@ -352,16 +796,13 @@ export class ApiController {
352
796
  my-wynk-app/
353
797
  ├── src/
354
798
  │ ├── controllers/
355
- │ │ ├── user.controller.ts
356
- │ │ └── auth.controller.ts
799
+ │ │ └── user.controller.ts
357
800
  │ ├── services/
358
- │ │ ├── user.service.ts
359
- │ │ └── auth.service.ts
360
- │ ├── middleware/
361
- │ │ ├── jwt.guard.ts
362
- │ │ └── roles.guard.ts
801
+ │ │ └── email.service.ts
363
802
  │ ├── dto/
364
803
  │ │ └── user.dto.ts
804
+ │ ├── exceptions/
805
+ │ │ └── email.exceptions.ts
365
806
  │ └── index.ts
366
807
  ├── package.json
367
808
  └── tsconfig.json
@@ -369,122 +810,285 @@ my-wynk-app/
369
810
 
370
811
  ---
371
812
 
372
- ## 🎨 Complete Example
813
+ ## 🎨 Complete Working Example
814
+
815
+ Here's a complete, production-ready example with all features:
373
816
 
374
817
  ```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";
818
+ // dto/user.dto.ts
819
+ import { DTO, CommonDTO } from "wynkjs";
820
+
821
+ export const CreateUserDTO = DTO.Strict({
822
+ name: DTO.Optional(DTO.String({ minLength: 2, maxLength: 50 })),
823
+ email: CommonDTO.Email({ description: "User email address" }),
824
+ mobile: DTO.Optional(
825
+ DTO.String({
826
+ pattern: "^[6-9]{1}[0-9]{9}$",
827
+ errorMessage: "Invalid mobile number",
828
+ })
829
+ ),
830
+ age: DTO.Optional(DTO.Number({ minimum: 18 })),
831
+ });
380
832
 
381
- const app = await WynkFramework.create({
382
- controllers: [UserController, AuthController],
383
- globalGuards: [],
384
- globalInterceptors: [],
833
+ export const UserIdDto = DTO.Object({
834
+ id: DTO.String({ minLength: 2, maxLength: 50 }),
385
835
  });
386
836
 
387
- await app.listen(3000);
388
- console.log("🚀 Server running on http://localhost:3000");
389
- ```
837
+ export interface CreateUserType {
838
+ name?: string;
839
+ email: string;
840
+ mobile?: string;
841
+ age?: number;
842
+ }
843
+
844
+ // services/email.service.ts
845
+ import { Injectable } from "wynkjs";
846
+
847
+ @Injectable()
848
+ export class EmailService {
849
+ async sendWelcomeEmail(email: string, userName: string): Promise<void> {
850
+ console.log(`📧 Sending welcome email to ${email}`);
851
+ // Your email sending logic (SendGrid, AWS SES, etc.)
852
+ }
853
+ }
390
854
 
391
- ```typescript
392
855
  // controllers/user.controller.ts
393
856
  import {
394
- Injectable,
395
- Inject,
396
857
  Controller,
397
858
  Get,
398
859
  Post,
399
- Put,
400
- Delete,
860
+ Patch,
401
861
  Body,
402
862
  Param,
403
- Use,
863
+ Injectable,
864
+ NotFoundException,
404
865
  } from "wynkjs";
405
- import { UserService } from "../services/user.service";
406
- import { jwtGuard } from "../middleware/jwt.guard";
866
+ import { CreateUserDTO, UserIdDto } from "../dto/user.dto";
867
+ import type { CreateUserType } from "../dto/user.dto";
868
+ import { EmailService } from "../services/email.service";
407
869
 
408
870
  @Injectable()
409
871
  @Controller("/users")
410
- @Use(jwtGuard)
411
872
  export class UserController {
412
- constructor(@Inject(UserService) private userService: UserService) {}
873
+ constructor(private emailService: EmailService) {}
413
874
 
414
875
  @Get("/")
415
876
  async list() {
416
- const users = await this.userService.findAll();
417
- return { users };
877
+ return { users: ["Alice", "Bob", "Charlie"] };
418
878
  }
419
879
 
420
- @Get("/:id")
421
- async findOne(@Param("id") id: string) {
422
- const user = await this.userService.findById(id);
423
- return { user };
880
+ @Post({ path: "/", body: CreateUserDTO })
881
+ async create(@Body() body: CreateUserType) {
882
+ // Send welcome email using injected service
883
+ if (body.email && body.name) {
884
+ await this.emailService.sendWelcomeEmail(body.email, body.name);
885
+ }
886
+ return { message: "User created", data: body };
424
887
  }
425
888
 
426
- @Post("/")
427
- async create(@Body() body: any) {
428
- const user = await this.userService.create(body);
429
- return { message: "User created", user };
889
+ @Get({ path: "/:id", params: UserIdDto })
890
+ async findOne(@Param("id") id: string) {
891
+ if (id === "nonexistent") {
892
+ throw new NotFoundException("User not found");
893
+ }
894
+ return { user: { id, name: "Alice" } };
430
895
  }
431
896
 
432
- @Put("/:id")
897
+ @Patch({ path: "/:id", params: UserIdDto })
433
898
  async update(@Param("id") id: string, @Body() body: any) {
434
- const user = await this.userService.update(id, body);
435
- return { message: "User updated", user };
899
+ return { message: "User updated", id, data: body };
436
900
  }
901
+ }
437
902
 
438
- @Delete("/:id")
439
- @HttpCode(204)
440
- async delete(@Param("id") id: string) {
441
- await this.userService.delete(id);
442
- }
903
+ // index.ts
904
+ import { WynkFactory } from "wynkjs";
905
+ import { UserController } from "./controllers/user.controller";
906
+
907
+ const app = WynkFactory.create({
908
+ controllers: [UserController],
909
+ });
910
+
911
+ await app.listen(3000);
912
+ console.log("🚀 Server running on http://localhost:3000");
913
+ ```
914
+
915
+ **Test the API:**
916
+
917
+ ```bash
918
+ # List all users
919
+ curl http://localhost:3000/users
920
+
921
+ # Create a new user (with validation and email)
922
+ curl -X POST http://localhost:3000/users \
923
+ -H "Content-Type: application/json" \
924
+ -d '{"name":"Alice","email":"alice@example.com","age":25}'
925
+
926
+ # Get user by ID
927
+ curl http://localhost:3000/users/123
928
+
929
+ # Update user
930
+ curl -X PATCH http://localhost:3000/users/123 \
931
+ -H "Content-Type: application/json" \
932
+ -d '{"email":"newemail@example.com"}'
933
+
934
+ # Test 404 exception
935
+ curl http://localhost:3000/users/nonexistent
936
+ ```
937
+
938
+ ---
939
+
940
+ ## 📖 API Reference
941
+
942
+ ### Core Decorators
943
+
944
+ #### `@Controller(basePath?: string)`
945
+
946
+ Define a controller class with optional base path.
947
+
948
+ ```typescript
949
+ @Controller("/users")
950
+ export class UserController {
951
+ // All routes will be prefixed with /users
443
952
  }
444
953
  ```
445
954
 
955
+ #### `@Get(path?: string)` / `@Post()` / `@Patch()` / `@Delete()`
956
+
957
+ HTTP method decorators with optional path and options.
958
+
446
959
  ```typescript
447
- // services/user.service.ts
960
+ @Get("/") // GET /users
961
+ @Post({ path: "/", body: CreateUserDTO }) // POST with validation
962
+ @Patch({ path: "/:id", params: UserIdDto }) // PATCH with param validation
963
+ ```
448
964
 
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
- ];
965
+ #### `@Body()` / `@Param(key?)` / `@Query(key?)`
455
966
 
456
- async findAll() {
457
- return this.users;
458
- }
967
+ Parameter extraction decorators.
459
968
 
460
- async findById(id: string) {
461
- return this.users.find((u) => u.id === id);
462
- }
969
+ ```typescript
970
+ async create(
971
+ @Body() body: CreateUserType, // Full body
972
+ @Param("id") id: string, // Single param
973
+ @Query() query: UserQueryType // Full query object
974
+ ) {}
975
+ ```
463
976
 
464
- async create(data: any) {
465
- const user = { id: Date.now().toString(), ...data };
466
- this.users.push(user);
467
- return user;
468
- }
977
+ #### `@Injectable()`
469
978
 
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
- }
979
+ Mark a class as injectable for dependency injection.
478
980
 
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
- }
981
+ ```typescript
982
+ @Injectable()
983
+ export class EmailService {
984
+ // This service can be injected into controllers
485
985
  }
486
986
  ```
487
987
 
988
+ ### DTO Helpers
989
+
990
+ #### `DTO.Strict(properties, options?)`
991
+
992
+ Create object schema that strips additional properties.
993
+
994
+ ```typescript
995
+ const UserDTO = DTO.Strict({
996
+ name: DTO.String(),
997
+ email: DTO.String({ format: "email" }),
998
+ });
999
+ ```
1000
+
1001
+ #### `CommonDTO` Patterns
1002
+
1003
+ Pre-built validation patterns for common use cases.
1004
+
1005
+ ```typescript
1006
+ CommonDTO.Email(); // Email validation
1007
+ CommonDTO.Name(); // Name (2-50 chars)
1008
+ CommonDTO.Password(); // Password (min 6 chars)
1009
+ CommonDTO.UUID(); // UUID format
1010
+ CommonDTO.PhoneIN(); // Indian phone number
1011
+ ```
1012
+
1013
+ ### Exception Classes
1014
+
1015
+ ```typescript
1016
+ throw new NotFoundException("User not found"); // 404
1017
+ throw new BadRequestException("Invalid input"); // 400
1018
+ throw new UnauthorizedException("Not authenticated"); // 401
1019
+ throw new ForbiddenException("Access denied"); // 403
1020
+ throw new InternalServerErrorException("Error"); // 500
1021
+ ```
1022
+
1023
+ ---
1024
+
1025
+ ## �️ CLI Tool
1026
+
1027
+ ### create-wynkjs
1028
+
1029
+ Quickly scaffold a new WynkJS project with best practices:
1030
+
1031
+ ```bash
1032
+ bunx create-wynkjs
1033
+ # or
1034
+ npx create-wynkjs
1035
+ ```
1036
+
1037
+ **Features:**
1038
+
1039
+ - 🎯 Interactive project setup
1040
+ - ✅ TypeScript configuration (strict mode)
1041
+ - 🔍 ESLint with TypeScript rules
1042
+ - 💅 Prettier for code formatting
1043
+ - 🪝 Husky for Git hooks (optional)
1044
+ - 🔥 Hot reload with `bun --watch` (faster than nodemon)
1045
+ - 📝 Complete working example (CRUD API)
1046
+
1047
+ **Generated Project Structure:**
1048
+
1049
+ ```
1050
+ my-wynkjs-app/
1051
+ ├── src/
1052
+ │ ├── controllers/
1053
+ │ │ └── user.controller.ts
1054
+ │ ├── services/
1055
+ │ │ └── user.service.ts
1056
+ │ ├── dto/
1057
+ │ │ └── user.dto.ts
1058
+ │ └── index.ts
1059
+ ├── .eslintrc.json
1060
+ ├── .prettierrc
1061
+ ├── tsconfig.json
1062
+ └── package.json
1063
+ ```
1064
+
1065
+ **Available Scripts:**
1066
+
1067
+ - `bun run dev` - Development with hot reload
1068
+ - `bun run start` - Production server
1069
+ - `bun run build` - Build TypeScript
1070
+ - `bun run lint` - Run ESLint
1071
+ - `bun run format` - Format with Prettier
1072
+
1073
+ [Learn more about create-wynkjs](./packages/create-wynkjs/README.md)
1074
+
1075
+ ---
1076
+
1077
+ ## �🔗 Resources
1078
+
1079
+ - 📚 [Full Documentation](https://github.com/wynkjs/wynkjs-core)
1080
+ - 🚀 [CLI Tool (create-wynkjs)](./packages/create-wynkjs/README.md)
1081
+ - 💡 [IntelliSense Guide](./docs/INTELLISENSE_GUIDE.md)
1082
+ - 🎨 [Validation Formatters](./VALIDATION_FORMATTERS.md)
1083
+ - 📝 [Changelog](./CHANGELOG.md)
1084
+ - 🐛 [Report Issues](https://github.com/wynkjs/wynkjs-core/issues)
1085
+
1086
+ ---
1087
+
1088
+ ## 🤝 Contributing
1089
+
1090
+ ```
1091
+
488
1092
  ---
489
1093
 
490
1094
  ## 🔧 API Reference
@@ -562,3 +1166,4 @@ Built with:
562
1166
  Made with ❤️ by [Alam Jamal](https://github.com/alamjamal)
563
1167
 
564
1168
  </div>
1169
+ ```
package/dist/dto.d.ts CHANGED
@@ -2,12 +2,14 @@
2
2
  * DTO Utilities for WynkJS Framework
3
3
  * Re-exports Elysia's TypeBox for DTO validation
4
4
  */
5
+ import { t, type TSchema } from "elysia";
5
6
  /**
6
- * Export Elysia's TypeBox as DTO builder
7
- * This provides runtime validation for request bodies, queries, params, etc.
7
+ * DTO Builder - Full TypeBox support with IntelliSense
8
+ *
9
+ * Provides runtime validation for request bodies, queries, params, etc.
8
10
  *
9
11
  * @example
10
- * import { DTO } from '@wynkjs/framework';
12
+ * import { DTO } from 'wynkjs';
11
13
  *
12
14
  * export const CreateUserDTO = DTO.Object({
13
15
  * name: DTO.String({ minLength: 2, maxLength: 50 }),
@@ -24,7 +26,14 @@
24
26
  * }
25
27
  * }
26
28
  */
27
- export declare const DTO: any;
29
+ export declare const DTO: typeof t & {
30
+ /**
31
+ * Create a strict object schema that strips additional properties
32
+ * @param properties - Object properties schema
33
+ * @param options - Additional schema options
34
+ */
35
+ Strict: (properties: Record<string, TSchema>, options?: Record<string, any>) => TSchema;
36
+ };
28
37
  /**
29
38
  * Common DTO patterns for quick use
30
39
  */
package/dist/dto.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../core/dto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,eAAO,MAAM,GAAG,EAAE,GAAO,CAAC;AAiC1B;;GAEG;AACH,eAAO,MAAM,SAAS;IACpB;;OAEG;;IAGH;;;OAGG;sBACc,GAAG;IAOpB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAQH;;OAEG;;IAGH;;OAEG;;;;;IAOH;;OAEG;mBACY,MAAM,EAAE;;;;CAKxB,CAAC;AAEF;;GAEG;AACH,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../core/dto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,GAAG,EAAQ,OAAO,CAAC,GAAG;IACjC;;;;OAIG;IACH,MAAM,EAAE,CACN,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC1B,OAAO,CAAC;CACd,CAAC;AAiCF;;GAEG;AACH,eAAO,MAAM,SAAS;IACpB;;OAEG;;IAGH;;;OAGG;sBACc,GAAG;IAOpB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAQH;;OAEG;;IAGH;;OAEG;;;;;IAOH;;OAEG;mBACY,MAAM,EAAE;;;;CAKxB,CAAC;AAEF;;GAEG;AACH,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC"}
package/dist/dto.js CHANGED
@@ -4,11 +4,12 @@
4
4
  */
5
5
  import { t } from "elysia";
6
6
  /**
7
- * Export Elysia's TypeBox as DTO builder
8
- * This provides runtime validation for request bodies, queries, params, etc.
7
+ * DTO Builder - Full TypeBox support with IntelliSense
8
+ *
9
+ * Provides runtime validation for request bodies, queries, params, etc.
9
10
  *
10
11
  * @example
11
- * import { DTO } from '@wynkjs/framework';
12
+ * import { DTO } from 'wynkjs';
12
13
  *
13
14
  * export const CreateUserDTO = DTO.Object({
14
15
  * name: DTO.String({ minLength: 2, maxLength: 50 }),
@@ -25,11 +26,6 @@ import { t } from "elysia";
25
26
  * }
26
27
  * }
27
28
  */
28
- // Note: Elysia's type builder exposes internal option types that TypeScript
29
- // cannot emit in d.ts files (TS4023). To keep declaration generation clean
30
- // while preserving runtime behavior, we export DTO with an `any` type.
31
- // Consumers still get runtime validation; for static typing, prefer using
32
- // `Static<TSchema>` from Elysia which we re-export below.
33
29
  export const DTO = t;
34
30
  /**
35
31
  * Helper to attach strict validation to a DTO Object schema
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wynkjs",
3
- "version": "1.0.1",
4
- "description": "A high-performance TypeScript framework built on Elysia with NestJS-style decorators - 20x faster than Express",
3
+ "version": "1.0.2",
4
+ "description": "A high-performance TypeScript framework built on Elysia for Bun with NestJS-style decorators - 20x faster than Express",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -10,6 +10,7 @@
10
10
  "wynk",
11
11
  "wynkjs",
12
12
  "elysia",
13
+ "bun",
13
14
  "framework",
14
15
  "typescript",
15
16
  "decorators",
@@ -45,11 +46,11 @@
45
46
  "devDependencies": {
46
47
  "elysia": "^1.0.0",
47
48
  "reflect-metadata": "^0.2.2",
48
- "@types/node": "^20.0.0",
49
+ "@types/bun": "latest",
49
50
  "typescript": "^5.0.0"
50
51
  },
51
52
  "engines": {
52
- "node": ">=18.0.0"
53
+ "bun": ">=1.0.0"
53
54
  },
54
55
  "exports": {
55
56
  ".": {