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 +739 -134
- package/dist/dto.d.ts +13 -4
- package/dist/dto.d.ts.map +1 -1
- package/dist/dto.js +4 -8
- 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,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
|
-
- 🔒 **
|
|
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)
|
|
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
|
-
|
|
66
|
+
bunx create-wynkjs
|
|
67
|
+
# or
|
|
68
|
+
npx create-wynkjs
|
|
46
69
|
```
|
|
47
70
|
|
|
48
|
-
|
|
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
|
|
93
|
+
### 1. Create Your DTOs (Data Transfer Objects)
|
|
59
94
|
|
|
60
95
|
```typescript
|
|
61
|
-
|
|
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
|
-
|
|
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
|
|
208
|
+
// index.ts
|
|
86
209
|
import { WynkFactory } from "wynkjs";
|
|
87
|
-
import { UserController } from "./
|
|
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
|
-
|
|
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
|
-
//
|
|
216
|
-
import { Injectable
|
|
516
|
+
// email.service.ts
|
|
517
|
+
import { Injectable } from "wynkjs";
|
|
217
518
|
|
|
218
519
|
@Injectable()
|
|
219
|
-
export class
|
|
220
|
-
async
|
|
221
|
-
|
|
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
|
-
|
|
542
|
+
// ✨ EmailService is automatically injected!
|
|
543
|
+
constructor(private emailService: EmailService) {}
|
|
229
544
|
|
|
230
|
-
@
|
|
231
|
-
async
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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/
|
|
258
|
-
import {
|
|
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 =
|
|
263
|
-
id:
|
|
264
|
-
name:
|
|
265
|
-
email:
|
|
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
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
age
|
|
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](./
|
|
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
|
-
│ │
|
|
356
|
-
│ │ └── auth.controller.ts
|
|
799
|
+
│ │ └── user.controller.ts
|
|
357
800
|
│ ├── services/
|
|
358
|
-
│ │
|
|
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
|
-
//
|
|
376
|
-
import "
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
|
382
|
-
|
|
383
|
-
globalGuards: [],
|
|
384
|
-
globalInterceptors: [],
|
|
833
|
+
export const UserIdDto = DTO.Object({
|
|
834
|
+
id: DTO.String({ minLength: 2, maxLength: 50 }),
|
|
385
835
|
});
|
|
386
836
|
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
|
|
400
|
-
Delete,
|
|
860
|
+
Patch,
|
|
401
861
|
Body,
|
|
402
862
|
Param,
|
|
403
|
-
|
|
863
|
+
Injectable,
|
|
864
|
+
NotFoundException,
|
|
404
865
|
} from "wynkjs";
|
|
405
|
-
import {
|
|
406
|
-
import {
|
|
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(
|
|
873
|
+
constructor(private emailService: EmailService) {}
|
|
413
874
|
|
|
414
875
|
@Get("/")
|
|
415
876
|
async list() {
|
|
416
|
-
|
|
417
|
-
return { users };
|
|
877
|
+
return { users: ["Alice", "Bob", "Charlie"] };
|
|
418
878
|
}
|
|
419
879
|
|
|
420
|
-
@
|
|
421
|
-
async
|
|
422
|
-
|
|
423
|
-
|
|
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
|
-
@
|
|
427
|
-
async
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
@
|
|
897
|
+
@Patch({ path: "/:id", params: UserIdDto })
|
|
433
898
|
async update(@Param("id") id: string, @Body() body: any) {
|
|
434
|
-
|
|
435
|
-
return { message: "User updated", user };
|
|
899
|
+
return { message: "User updated", id, data: body };
|
|
436
900
|
}
|
|
901
|
+
}
|
|
437
902
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
457
|
-
return this.users;
|
|
458
|
-
}
|
|
967
|
+
Parameter extraction decorators.
|
|
459
968
|
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
465
|
-
const user = { id: Date.now().toString(), ...data };
|
|
466
|
-
this.users.push(user);
|
|
467
|
-
return user;
|
|
468
|
-
}
|
|
977
|
+
#### `@Injectable()`
|
|
469
978
|
|
|
470
|
-
|
|
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
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
*
|
|
7
|
-
*
|
|
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 '
|
|
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:
|
|
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;
|
|
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
|
-
*
|
|
8
|
-
*
|
|
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 '
|
|
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.
|
|
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/
|
|
49
|
+
"@types/bun": "latest",
|
|
49
50
|
"typescript": "^5.0.0"
|
|
50
51
|
},
|
|
51
52
|
"engines": {
|
|
52
|
-
"
|
|
53
|
+
"bun": ">=1.0.0"
|
|
53
54
|
},
|
|
54
55
|
"exports": {
|
|
55
56
|
".": {
|