wynkjs 1.0.0 → 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 +776 -129
- package/dist/decorators/exception.advanced.d.ts +43 -14
- package/dist/decorators/exception.advanced.d.ts.map +1 -1
- package/dist/decorators/exception.advanced.js +132 -15
- package/dist/decorators/http.decorators.d.ts +14 -12
- package/dist/decorators/http.decorators.d.ts.map +1 -1
- package/dist/decorators/http.decorators.js +34 -16
- package/dist/dto.d.ts +15 -5
- package/dist/dto.d.ts.map +1 -1
- package/dist/dto.js +37 -9
- package/dist/factory.d.ts +3 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +87 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/package.json +5 -4
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
|
[](https://www.npmjs.com/package/wynkjs)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
|
+
[](https://bun.sh/)
|
|
10
11
|
|
|
11
|
-
_20x faster than Express, easier than
|
|
12
|
+
_20x faster than Express, easier than NestJS, built for Bun_ ⚡
|
|
12
13
|
|
|
13
|
-
[
|
|
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
|
|
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
|
-
|
|
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,66 +43,173 @@ 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
|
-
- 💉 **Dependency Injection** - Built-in DI
|
|
34
|
-
- 🔒 **
|
|
48
|
+
- 💉 **Dependency Injection** - Built-in DI (no need to import reflect-metadata!)
|
|
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
|
-
- ⚡ **
|
|
52
|
+
- ⚡ **Bun Only** - Built exclusively for Bun runtime (not Node.js)
|
|
53
|
+
- 📦 **Single Import** - Everything from `wynkjs` (Injectable, Controller, Get, etc.)
|
|
38
54
|
|
|
39
55
|
---
|
|
40
56
|
|
|
41
57
|
## 📦 Installation
|
|
42
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
|
+
|
|
43
65
|
```bash
|
|
44
|
-
|
|
66
|
+
bunx create-wynkjs
|
|
67
|
+
# or
|
|
68
|
+
npx create-wynkjs
|
|
45
69
|
```
|
|
46
70
|
|
|
47
|
-
|
|
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:
|
|
48
82
|
|
|
49
83
|
```bash
|
|
50
|
-
bun add wynkjs elysia
|
|
84
|
+
bun add wynkjs elysia
|
|
51
85
|
```
|
|
52
86
|
|
|
87
|
+
**Note**: WynkJS is built specifically for **Bun**. It leverages Elysia's performance optimizations that are designed for Bun runtime. ✨
|
|
88
|
+
|
|
53
89
|
---
|
|
54
90
|
|
|
55
91
|
## 🚀 Quick Start
|
|
56
92
|
|
|
57
|
-
### 1. Create Your
|
|
93
|
+
### 1. Create Your DTOs (Data Transfer Objects)
|
|
58
94
|
|
|
59
95
|
```typescript
|
|
60
|
-
|
|
61
|
-
import {
|
|
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
|
+
});
|
|
62
123
|
|
|
63
|
-
|
|
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";
|
|
162
|
+
|
|
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
|
-
|
|
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
|
-
###
|
|
205
|
+
### 4. Bootstrap Your Application
|
|
84
206
|
|
|
85
207
|
```typescript
|
|
86
|
-
|
|
87
|
-
import {
|
|
88
|
-
import { UserController } from "./
|
|
208
|
+
// index.ts
|
|
209
|
+
import { WynkFactory } from "wynkjs";
|
|
210
|
+
import { UserController } from "./user.controller";
|
|
89
211
|
|
|
90
|
-
const app =
|
|
212
|
+
const app = WynkFactory.create({
|
|
91
213
|
controllers: [UserController],
|
|
92
214
|
});
|
|
93
215
|
|
|
@@ -96,10 +218,32 @@ await app.listen(3000);
|
|
|
96
218
|
console.log("🚀 Server running on http://localhost:3000");
|
|
97
219
|
```
|
|
98
220
|
|
|
99
|
-
###
|
|
221
|
+
### 5. Run Your Server
|
|
100
222
|
|
|
101
223
|
```bash
|
|
102
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"}'
|
|
103
247
|
```
|
|
104
248
|
|
|
105
249
|
That's it! 🎉
|
|
@@ -151,6 +295,162 @@ That's it! 🎉
|
|
|
151
295
|
|
|
152
296
|
---
|
|
153
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
|
+
|
|
154
454
|
## 🎯 Features & Examples
|
|
155
455
|
|
|
156
456
|
### 🔒 Authentication with Guards
|
|
@@ -210,47 +510,78 @@ export class AdminController {
|
|
|
210
510
|
|
|
211
511
|
### 💉 Dependency Injection
|
|
212
512
|
|
|
513
|
+
WynkJS includes powerful dependency injection with **zero setup required**:
|
|
514
|
+
|
|
213
515
|
```typescript
|
|
214
|
-
|
|
516
|
+
// email.service.ts
|
|
517
|
+
import { Injectable } from "wynkjs";
|
|
518
|
+
|
|
519
|
+
@Injectable()
|
|
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
|
+
}
|
|
215
525
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
|
220
532
|
}
|
|
221
533
|
}
|
|
222
534
|
|
|
223
|
-
|
|
535
|
+
// user.controller.ts
|
|
536
|
+
import { Controller, Post, Body, Injectable } from "wynkjs";
|
|
537
|
+
import { EmailService } from "./email.service";
|
|
538
|
+
|
|
539
|
+
@Injectable()
|
|
224
540
|
@Controller("/users")
|
|
225
541
|
export class UserController {
|
|
226
|
-
|
|
542
|
+
// ✨ EmailService is automatically injected!
|
|
543
|
+
constructor(private emailService: EmailService) {}
|
|
227
544
|
|
|
228
|
-
@
|
|
229
|
-
async
|
|
230
|
-
|
|
231
|
-
|
|
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!" };
|
|
550
|
+
}
|
|
551
|
+
|
|
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" };
|
|
232
559
|
}
|
|
233
560
|
}
|
|
234
561
|
```
|
|
235
562
|
|
|
563
|
+
**Available DI decorators**:
|
|
564
|
+
|
|
565
|
+
- Capital: `Injectable`, `Inject`, `Singleton`, `AutoInjectable`, `Container`
|
|
566
|
+
|
|
236
567
|
### 🗃️ Database Integration (Drizzle ORM)
|
|
237
568
|
|
|
238
569
|
```typescript
|
|
239
|
-
import { drizzle } from "drizzle-orm/
|
|
240
|
-
import {
|
|
570
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
571
|
+
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
|
241
572
|
import { InjectTable, registerTables } from "wynkjs";
|
|
242
573
|
|
|
243
574
|
// Define your table
|
|
244
|
-
const userTable =
|
|
245
|
-
id:
|
|
246
|
-
name:
|
|
247
|
-
email:
|
|
575
|
+
const userTable = sqliteTable("users", {
|
|
576
|
+
id: integer("id").primaryKey(),
|
|
577
|
+
name: text("name").notNull(),
|
|
578
|
+
email: text("email").notNull().unique(),
|
|
248
579
|
});
|
|
249
580
|
|
|
250
581
|
// Register tables
|
|
251
582
|
registerTables({ userTable });
|
|
252
583
|
|
|
253
|
-
@
|
|
584
|
+
@Injectable()
|
|
254
585
|
export class UserService {
|
|
255
586
|
private db = drizzle(process.env.DATABASE_URL);
|
|
256
587
|
|
|
@@ -264,14 +595,84 @@ export class UserService {
|
|
|
264
595
|
|
|
265
596
|
### 📝 Request Validation
|
|
266
597
|
|
|
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)
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
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
|
+
});
|
|
620
|
+
|
|
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
|
+
|
|
267
667
|
```typescript
|
|
268
|
-
import {
|
|
269
|
-
import { t } from "elysia";
|
|
668
|
+
import { WynkFactory, FormatErrorFormatter } from "wynkjs";
|
|
270
669
|
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
|
275
676
|
});
|
|
276
677
|
|
|
277
678
|
@Controller("/users")
|
|
@@ -285,6 +686,82 @@ export class UserController {
|
|
|
285
686
|
return { message: "User created", data: body };
|
|
286
687
|
}
|
|
287
688
|
}
|
|
689
|
+
|
|
690
|
+
// Choose your validation error format
|
|
691
|
+
const app = WynkFactory.create({
|
|
692
|
+
controllers: [UserController],
|
|
693
|
+
// Option 1: Default format (recommended)
|
|
694
|
+
// validationErrorFormatter: new FormatErrorFormatter(), // NestJS-style
|
|
695
|
+
// Option 2: Simple array format
|
|
696
|
+
// validationErrorFormatter: new SimpleErrorFormatter(),
|
|
697
|
+
// Option 3: Detailed format with field info
|
|
698
|
+
// validationErrorFormatter: new DetailedErrorFormatter(),
|
|
699
|
+
});
|
|
700
|
+
```
|
|
701
|
+
|
|
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
|
+
}
|
|
288
765
|
```
|
|
289
766
|
|
|
290
767
|
### 🔄 Multiple Middleware
|
|
@@ -319,16 +796,13 @@ export class ApiController {
|
|
|
319
796
|
my-wynk-app/
|
|
320
797
|
├── src/
|
|
321
798
|
│ ├── controllers/
|
|
322
|
-
│ │
|
|
323
|
-
│ │ └── auth.controller.ts
|
|
799
|
+
│ │ └── user.controller.ts
|
|
324
800
|
│ ├── services/
|
|
325
|
-
│ │
|
|
326
|
-
│ │ └── auth.service.ts
|
|
327
|
-
│ ├── middleware/
|
|
328
|
-
│ │ ├── jwt.guard.ts
|
|
329
|
-
│ │ └── roles.guard.ts
|
|
801
|
+
│ │ └── email.service.ts
|
|
330
802
|
│ ├── dto/
|
|
331
803
|
│ │ └── user.dto.ts
|
|
804
|
+
│ ├── exceptions/
|
|
805
|
+
│ │ └── email.exceptions.ts
|
|
332
806
|
│ └── index.ts
|
|
333
807
|
├── package.json
|
|
334
808
|
└── tsconfig.json
|
|
@@ -336,113 +810,285 @@ my-wynk-app/
|
|
|
336
810
|
|
|
337
811
|
---
|
|
338
812
|
|
|
339
|
-
## 🎨 Complete Example
|
|
813
|
+
## 🎨 Complete Working Example
|
|
814
|
+
|
|
815
|
+
Here's a complete, production-ready example with all features:
|
|
340
816
|
|
|
341
817
|
```typescript
|
|
342
|
-
//
|
|
343
|
-
import "
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
+
});
|
|
347
832
|
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
globalGuards: [],
|
|
351
|
-
globalInterceptors: [],
|
|
833
|
+
export const UserIdDto = DTO.Object({
|
|
834
|
+
id: DTO.String({ minLength: 2, maxLength: 50 }),
|
|
352
835
|
});
|
|
353
836
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
837
|
+
export interface CreateUserType {
|
|
838
|
+
name?: string;
|
|
839
|
+
email: string;
|
|
840
|
+
mobile?: string;
|
|
841
|
+
age?: number;
|
|
842
|
+
}
|
|
357
843
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
import { Controller, Get, Post, Put, Delete, Body, Param, Use } from "wynkjs";
|
|
361
|
-
import { injectable, inject } from "tsyringe";
|
|
362
|
-
import { UserService } from "../services/user.service";
|
|
363
|
-
import { jwtGuard } from "../middleware/jwt.guard";
|
|
844
|
+
// services/email.service.ts
|
|
845
|
+
import { Injectable } from "wynkjs";
|
|
364
846
|
|
|
365
|
-
@
|
|
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
|
+
}
|
|
854
|
+
|
|
855
|
+
// controllers/user.controller.ts
|
|
856
|
+
import {
|
|
857
|
+
Controller,
|
|
858
|
+
Get,
|
|
859
|
+
Post,
|
|
860
|
+
Patch,
|
|
861
|
+
Body,
|
|
862
|
+
Param,
|
|
863
|
+
Injectable,
|
|
864
|
+
NotFoundException,
|
|
865
|
+
} from "wynkjs";
|
|
866
|
+
import { CreateUserDTO, UserIdDto } from "../dto/user.dto";
|
|
867
|
+
import type { CreateUserType } from "../dto/user.dto";
|
|
868
|
+
import { EmailService } from "../services/email.service";
|
|
869
|
+
|
|
870
|
+
@Injectable()
|
|
366
871
|
@Controller("/users")
|
|
367
|
-
@Use(jwtGuard)
|
|
368
872
|
export class UserController {
|
|
369
|
-
constructor(
|
|
873
|
+
constructor(private emailService: EmailService) {}
|
|
370
874
|
|
|
371
875
|
@Get("/")
|
|
372
876
|
async list() {
|
|
373
|
-
|
|
374
|
-
return { users };
|
|
877
|
+
return { users: ["Alice", "Bob", "Charlie"] };
|
|
375
878
|
}
|
|
376
879
|
|
|
377
|
-
@
|
|
378
|
-
async
|
|
379
|
-
|
|
380
|
-
|
|
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 };
|
|
381
887
|
}
|
|
382
888
|
|
|
383
|
-
@
|
|
384
|
-
async
|
|
385
|
-
|
|
386
|
-
|
|
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" } };
|
|
387
895
|
}
|
|
388
896
|
|
|
389
|
-
@
|
|
897
|
+
@Patch({ path: "/:id", params: UserIdDto })
|
|
390
898
|
async update(@Param("id") id: string, @Body() body: any) {
|
|
391
|
-
|
|
392
|
-
return { message: "User updated", user };
|
|
899
|
+
return { message: "User updated", id, data: body };
|
|
393
900
|
}
|
|
901
|
+
}
|
|
394
902
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
|
400
952
|
}
|
|
401
953
|
```
|
|
402
954
|
|
|
955
|
+
#### `@Get(path?: string)` / `@Post()` / `@Patch()` / `@Delete()`
|
|
956
|
+
|
|
957
|
+
HTTP method decorators with optional path and options.
|
|
958
|
+
|
|
403
959
|
```typescript
|
|
404
|
-
//
|
|
405
|
-
|
|
960
|
+
@Get("/") // GET /users
|
|
961
|
+
@Post({ path: "/", body: CreateUserDTO }) // POST with validation
|
|
962
|
+
@Patch({ path: "/:id", params: UserIdDto }) // PATCH with param validation
|
|
963
|
+
```
|
|
406
964
|
|
|
407
|
-
|
|
408
|
-
export class UserService {
|
|
409
|
-
private users = [
|
|
410
|
-
{ id: "1", name: "Alice", email: "alice@example.com" },
|
|
411
|
-
{ id: "2", name: "Bob", email: "bob@example.com" },
|
|
412
|
-
];
|
|
965
|
+
#### `@Body()` / `@Param(key?)` / `@Query(key?)`
|
|
413
966
|
|
|
414
|
-
|
|
415
|
-
return this.users;
|
|
416
|
-
}
|
|
967
|
+
Parameter extraction decorators.
|
|
417
968
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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
|
+
```
|
|
421
976
|
|
|
422
|
-
|
|
423
|
-
const user = { id: Date.now().toString(), ...data };
|
|
424
|
-
this.users.push(user);
|
|
425
|
-
return user;
|
|
426
|
-
}
|
|
977
|
+
#### `@Injectable()`
|
|
427
978
|
|
|
428
|
-
|
|
429
|
-
const index = this.users.findIndex((u) => u.id === id);
|
|
430
|
-
if (index !== -1) {
|
|
431
|
-
this.users[index] = { ...this.users[index], ...data };
|
|
432
|
-
return this.users[index];
|
|
433
|
-
}
|
|
434
|
-
return null;
|
|
435
|
-
}
|
|
979
|
+
Mark a class as injectable for dependency injection.
|
|
436
980
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
}
|
|
981
|
+
```typescript
|
|
982
|
+
@Injectable()
|
|
983
|
+
export class EmailService {
|
|
984
|
+
// This service can be injected into controllers
|
|
443
985
|
}
|
|
444
986
|
```
|
|
445
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
|
+
|
|
446
1092
|
---
|
|
447
1093
|
|
|
448
1094
|
## 🔧 API Reference
|
|
@@ -520,3 +1166,4 @@ Built with:
|
|
|
520
1166
|
Made with ❤️ by [Alam Jamal](https://github.com/alamjamal)
|
|
521
1167
|
|
|
522
1168
|
</div>
|
|
1169
|
+
```
|