wynkjs 1.0.0
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/LICENSE +21 -0
- package/README.md +522 -0
- package/dist/database.d.ts +36 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +162 -0
- package/dist/decorators/database.decorators.d.ts +55 -0
- package/dist/decorators/database.decorators.d.ts.map +1 -0
- package/dist/decorators/database.decorators.js +131 -0
- package/dist/decorators/exception.advanced.d.ts +160 -0
- package/dist/decorators/exception.advanced.d.ts.map +1 -0
- package/dist/decorators/exception.advanced.js +232 -0
- package/dist/decorators/exception.decorators.d.ts +121 -0
- package/dist/decorators/exception.decorators.d.ts.map +1 -0
- package/dist/decorators/exception.decorators.js +242 -0
- package/dist/decorators/guard.decorators.d.ts +43 -0
- package/dist/decorators/guard.decorators.d.ts.map +1 -0
- package/dist/decorators/guard.decorators.js +67 -0
- package/dist/decorators/http.decorators.d.ts +130 -0
- package/dist/decorators/http.decorators.d.ts.map +1 -0
- package/dist/decorators/http.decorators.js +209 -0
- package/dist/decorators/interceptor.advanced.d.ts +93 -0
- package/dist/decorators/interceptor.advanced.d.ts.map +1 -0
- package/dist/decorators/interceptor.advanced.js +228 -0
- package/dist/decorators/interceptor.decorators.d.ts +91 -0
- package/dist/decorators/interceptor.decorators.d.ts.map +1 -0
- package/dist/decorators/interceptor.decorators.js +163 -0
- package/dist/decorators/param.decorators.d.ts +144 -0
- package/dist/decorators/param.decorators.d.ts.map +1 -0
- package/dist/decorators/param.decorators.js +205 -0
- package/dist/decorators/pipe.advanced.d.ts +125 -0
- package/dist/decorators/pipe.advanced.d.ts.map +1 -0
- package/dist/decorators/pipe.advanced.js +263 -0
- package/dist/decorators/pipe.decorators.d.ts +226 -0
- package/dist/decorators/pipe.decorators.d.ts.map +1 -0
- package/dist/decorators/pipe.decorators.js +420 -0
- package/dist/dto.d.ts +83 -0
- package/dist/dto.d.ts.map +1 -0
- package/dist/dto.js +88 -0
- package/dist/factory.d.ts +76 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +410 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/pipes/validation.pipe.d.ts +91 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +163 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alam Jamal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# 🚀 WynkJS
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
**A high-performance TypeScript framework built on Elysia with NestJS-style decorators**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/wynkjs)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
|
|
11
|
+
_20x faster than Express, easier than NestJS_ ⚡
|
|
12
|
+
|
|
13
|
+
[Documentation](#documentation) • [Quick Start](#quick-start) • [Examples](#examples) • [Features](#features)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## About
|
|
20
|
+
|
|
21
|
+
WynkJS is a modern, TypeScript-first web framework that brings NestJS-style decorators to the blazing-fast Elysia runtime. 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 Node.js or Bun. WynkJS embraces ESM, ships first-class types, and keeps things simple so you can move fast without the bloat.
|
|
22
|
+
|
|
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
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ✨ Why WynkJS?
|
|
28
|
+
|
|
29
|
+
WynkJS combines the **speed of Elysia** with the **elegant decorator syntax of NestJS**, giving you the best of both worlds:
|
|
30
|
+
|
|
31
|
+
- 🚀 **20x Faster** - Built on Elysia, one of the fastest web frameworks
|
|
32
|
+
- 🎨 **Decorator-Based** - Familiar NestJS-style decorators
|
|
33
|
+
- 💉 **Dependency Injection** - Built-in DI with tsyringe
|
|
34
|
+
- 🔒 **Type-Safe** - Full TypeScript support
|
|
35
|
+
- 🎯 **Simple & Clean** - Easy to learn, powerful to use
|
|
36
|
+
- 🔌 **Middleware Support** - Guards, interceptors, pipes, filters
|
|
37
|
+
- ⚡ **Hot Reload** - Fast development with Bun
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 📦 Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install wynkjs elysia reflect-metadata
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or with Bun:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
bun add wynkjs elysia reflect-metadata
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🚀 Quick Start
|
|
56
|
+
|
|
57
|
+
### 1. Create Your First Controller
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { Controller, Get, Post, Body } from "wynkjs";
|
|
61
|
+
import { injectable } from "tsyringe";
|
|
62
|
+
|
|
63
|
+
@injectable()
|
|
64
|
+
@Controller("/users")
|
|
65
|
+
export class UserController {
|
|
66
|
+
@Get("/")
|
|
67
|
+
async list() {
|
|
68
|
+
return { users: ["Alice", "Bob", "Charlie"] };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Post("/")
|
|
72
|
+
async create(@Body() body: any) {
|
|
73
|
+
return { message: "User created", data: body };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@Get("/:id")
|
|
77
|
+
async findOne(@Param("id") id: string) {
|
|
78
|
+
return { user: { id, name: "Alice" } };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Create Your Application
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import "reflect-metadata";
|
|
87
|
+
import { WynkFramework } from "wynkjs";
|
|
88
|
+
import { UserController } from "./controllers/user.controller";
|
|
89
|
+
|
|
90
|
+
const app = await WynkFramework.create({
|
|
91
|
+
controllers: [UserController],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await app.listen(3000);
|
|
95
|
+
|
|
96
|
+
console.log("🚀 Server running on http://localhost:3000");
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Run Your Server
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
bun run index.ts
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
That's it! 🎉
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 📚 Core Decorators
|
|
110
|
+
|
|
111
|
+
### HTTP Methods
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
@Get(path?: string) // GET request
|
|
115
|
+
@Post(path?: string) // POST request
|
|
116
|
+
@Put(path?: string) // PUT request
|
|
117
|
+
@Patch(path?: string) // PATCH request
|
|
118
|
+
@Delete(path?: string) // DELETE request
|
|
119
|
+
@Options(path?: string) // OPTIONS request
|
|
120
|
+
@Head(path?: string) // HEAD request
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Parameter Decorators
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
@Param(key?: string) // Route parameters
|
|
127
|
+
@Body() // Request body
|
|
128
|
+
@Query(key?: string) // Query parameters
|
|
129
|
+
@Headers(key?: string) // Request headers
|
|
130
|
+
@Req() // Full request object
|
|
131
|
+
@Res() // Full response object
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Route Options
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
@HttpCode(statusCode) // Set HTTP status code
|
|
138
|
+
@Header(name, value) // Set response header
|
|
139
|
+
@Redirect(url, code?) // Redirect response
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Middleware
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
@Use(...middlewares) // Apply middleware
|
|
146
|
+
@UseGuards(...guards) // Apply guards
|
|
147
|
+
@UseInterceptors(...) // Apply interceptors
|
|
148
|
+
@UsePipes(...pipes) // Apply pipes
|
|
149
|
+
@UseFilters(...filters) // Apply exception filters
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 🎯 Features & Examples
|
|
155
|
+
|
|
156
|
+
### 🔒 Authentication with Guards
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { Controller, Get, Use } from "wynkjs";
|
|
160
|
+
|
|
161
|
+
// Create a simple JWT guard
|
|
162
|
+
const jwtGuard = async (ctx: any, next: Function) => {
|
|
163
|
+
const token = ctx.headers.authorization?.replace("Bearer ", "");
|
|
164
|
+
|
|
165
|
+
if (!token) {
|
|
166
|
+
ctx.set.status = 401;
|
|
167
|
+
return { error: "Unauthorized" };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Verify token and attach user
|
|
171
|
+
ctx.user = await verifyToken(token);
|
|
172
|
+
return next();
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
@Controller("/protected")
|
|
176
|
+
export class ProtectedController {
|
|
177
|
+
@Get("/")
|
|
178
|
+
@Use(jwtGuard)
|
|
179
|
+
async getProtectedData() {
|
|
180
|
+
return { message: "This is protected!" };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 🎭 Role-Based Access Control
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const rolesGuard = (allowedRoles: string[]) => {
|
|
189
|
+
return async (ctx: any, next: Function) => {
|
|
190
|
+
const userRole = ctx.user?.role;
|
|
191
|
+
|
|
192
|
+
if (!allowedRoles.includes(userRole)) {
|
|
193
|
+
ctx.set.status = 403;
|
|
194
|
+
return { error: "Forbidden" };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return next();
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
@Controller("/admin")
|
|
202
|
+
@Use(jwtGuard, rolesGuard(["admin"]))
|
|
203
|
+
export class AdminController {
|
|
204
|
+
@Get("/users")
|
|
205
|
+
async getAllUsers() {
|
|
206
|
+
return { users: [] };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 💉 Dependency Injection
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { injectable, inject } from "tsyringe";
|
|
215
|
+
|
|
216
|
+
@injectable()
|
|
217
|
+
export class UserService {
|
|
218
|
+
async findAll() {
|
|
219
|
+
return [{ id: 1, name: "Alice" }];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@injectable()
|
|
224
|
+
@Controller("/users")
|
|
225
|
+
export class UserController {
|
|
226
|
+
constructor(@inject(UserService) private userService: UserService) {}
|
|
227
|
+
|
|
228
|
+
@Get("/")
|
|
229
|
+
async list() {
|
|
230
|
+
const users = await this.userService.findAll();
|
|
231
|
+
return { users };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 🗃️ Database Integration (Drizzle ORM)
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { drizzle } from "drizzle-orm/node-postgres";
|
|
240
|
+
import { pgTable, varchar } from "drizzle-orm/pg-core";
|
|
241
|
+
import { InjectTable, registerTables } from "wynkjs";
|
|
242
|
+
|
|
243
|
+
// Define your table
|
|
244
|
+
const userTable = pgTable("users", {
|
|
245
|
+
id: varchar("id").primaryKey(),
|
|
246
|
+
name: varchar("name").notNull(),
|
|
247
|
+
email: varchar("email").notNull().unique(),
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Register tables
|
|
251
|
+
registerTables({ userTable });
|
|
252
|
+
|
|
253
|
+
@injectable()
|
|
254
|
+
export class UserService {
|
|
255
|
+
private db = drizzle(process.env.DATABASE_URL);
|
|
256
|
+
|
|
257
|
+
constructor(@InjectTable(userTable) private table: typeof userTable) {}
|
|
258
|
+
|
|
259
|
+
async findAll() {
|
|
260
|
+
return this.db.select().from(this.table);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 📝 Request Validation
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { Post, Body, UsePipes } from "wynkjs";
|
|
269
|
+
import { t } from "elysia";
|
|
270
|
+
|
|
271
|
+
const CreateUserDTO = t.Object({
|
|
272
|
+
name: t.String({ minLength: 2 }),
|
|
273
|
+
email: t.String({ format: "email" }),
|
|
274
|
+
password: t.String({ minLength: 8 }),
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
@Controller("/users")
|
|
278
|
+
export class UserController {
|
|
279
|
+
@Post({
|
|
280
|
+
path: "/",
|
|
281
|
+
body: CreateUserDTO,
|
|
282
|
+
})
|
|
283
|
+
async create(@Body() body: any) {
|
|
284
|
+
// Body is automatically validated!
|
|
285
|
+
return { message: "User created", data: body };
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### 🔄 Multiple Middleware
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const logger = async (ctx: any, next: Function) => {
|
|
294
|
+
console.log(`${ctx.request.method} ${ctx.path}`);
|
|
295
|
+
return next();
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const cors = async (ctx: any, next: Function) => {
|
|
299
|
+
ctx.set.headers["Access-Control-Allow-Origin"] = "*";
|
|
300
|
+
return next();
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
@Controller("/api")
|
|
304
|
+
@Use(logger, cors)
|
|
305
|
+
export class ApiController {
|
|
306
|
+
@Get("/data")
|
|
307
|
+
@Use(cacheMiddleware)
|
|
308
|
+
async getData() {
|
|
309
|
+
return { data: [] };
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 🏗️ Project Structure
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
my-wynk-app/
|
|
320
|
+
├── src/
|
|
321
|
+
│ ├── controllers/
|
|
322
|
+
│ │ ├── user.controller.ts
|
|
323
|
+
│ │ └── auth.controller.ts
|
|
324
|
+
│ ├── services/
|
|
325
|
+
│ │ ├── user.service.ts
|
|
326
|
+
│ │ └── auth.service.ts
|
|
327
|
+
│ ├── middleware/
|
|
328
|
+
│ │ ├── jwt.guard.ts
|
|
329
|
+
│ │ └── roles.guard.ts
|
|
330
|
+
│ ├── dto/
|
|
331
|
+
│ │ └── user.dto.ts
|
|
332
|
+
│ └── index.ts
|
|
333
|
+
├── package.json
|
|
334
|
+
└── tsconfig.json
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## 🎨 Complete Example
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// index.ts
|
|
343
|
+
import "reflect-metadata";
|
|
344
|
+
import { WynkFramework } from "wynkjs";
|
|
345
|
+
import { UserController } from "./controllers/user.controller";
|
|
346
|
+
import { AuthController } from "./controllers/auth.controller";
|
|
347
|
+
|
|
348
|
+
const app = await WynkFramework.create({
|
|
349
|
+
controllers: [UserController, AuthController],
|
|
350
|
+
globalGuards: [],
|
|
351
|
+
globalInterceptors: [],
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
await app.listen(3000);
|
|
355
|
+
console.log("🚀 Server running on http://localhost:3000");
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// controllers/user.controller.ts
|
|
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";
|
|
364
|
+
|
|
365
|
+
@injectable()
|
|
366
|
+
@Controller("/users")
|
|
367
|
+
@Use(jwtGuard)
|
|
368
|
+
export class UserController {
|
|
369
|
+
constructor(@inject(UserService) private userService: UserService) {}
|
|
370
|
+
|
|
371
|
+
@Get("/")
|
|
372
|
+
async list() {
|
|
373
|
+
const users = await this.userService.findAll();
|
|
374
|
+
return { users };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
@Get("/:id")
|
|
378
|
+
async findOne(@Param("id") id: string) {
|
|
379
|
+
const user = await this.userService.findById(id);
|
|
380
|
+
return { user };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
@Post("/")
|
|
384
|
+
async create(@Body() body: any) {
|
|
385
|
+
const user = await this.userService.create(body);
|
|
386
|
+
return { message: "User created", user };
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
@Put("/:id")
|
|
390
|
+
async update(@Param("id") id: string, @Body() body: any) {
|
|
391
|
+
const user = await this.userService.update(id, body);
|
|
392
|
+
return { message: "User updated", user };
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
@Delete("/:id")
|
|
396
|
+
@HttpCode(204)
|
|
397
|
+
async delete(@Param("id") id: string) {
|
|
398
|
+
await this.userService.delete(id);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
// services/user.service.ts
|
|
405
|
+
import { injectable } from "tsyringe";
|
|
406
|
+
|
|
407
|
+
@injectable()
|
|
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
|
+
];
|
|
413
|
+
|
|
414
|
+
async findAll() {
|
|
415
|
+
return this.users;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async findById(id: string) {
|
|
419
|
+
return this.users.find((u) => u.id === id);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async create(data: any) {
|
|
423
|
+
const user = { id: Date.now().toString(), ...data };
|
|
424
|
+
this.users.push(user);
|
|
425
|
+
return user;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async update(id: string, data: any) {
|
|
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
|
+
}
|
|
436
|
+
|
|
437
|
+
async delete(id: string) {
|
|
438
|
+
const index = this.users.findIndex((u) => u.id === id);
|
|
439
|
+
if (index !== -1) {
|
|
440
|
+
this.users.splice(index, 1);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## 🔧 API Reference
|
|
449
|
+
|
|
450
|
+
### WynkFramework.create(options)
|
|
451
|
+
|
|
452
|
+
Create a new WynkJS application.
|
|
453
|
+
|
|
454
|
+
**Options:**
|
|
455
|
+
|
|
456
|
+
- `controllers: Array<Class>` - Array of controller classes
|
|
457
|
+
- `globalGuards?: Array<Guard>` - Global guards (optional)
|
|
458
|
+
- `globalInterceptors?: Array<Interceptor>` - Global interceptors (optional)
|
|
459
|
+
- `globalPipes?: Array<Pipe>` - Global pipes (optional)
|
|
460
|
+
- `globalFilters?: Array<Filter>` - Global exception filters (optional)
|
|
461
|
+
|
|
462
|
+
**Returns:** Promise<WynkFramework>
|
|
463
|
+
|
|
464
|
+
### app.listen(port, callback?)
|
|
465
|
+
|
|
466
|
+
Start the server on the specified port.
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## 🎯 Performance
|
|
471
|
+
|
|
472
|
+
WynkJS is built on Elysia, which is **20x faster than Express**:
|
|
473
|
+
|
|
474
|
+
| Framework | Requests/sec | Latency (avg) |
|
|
475
|
+
| ---------- | ------------ | ------------- |
|
|
476
|
+
| **WynkJS** | **~250,000** | **~0.4ms** |
|
|
477
|
+
| Elysia | ~250,000 | ~0.4ms |
|
|
478
|
+
| Fastify | ~45,000 | ~2.2ms |
|
|
479
|
+
| Express | ~12,000 | ~8.3ms |
|
|
480
|
+
|
|
481
|
+
_Benchmarks may vary based on hardware and configuration_
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## 🤝 Contributing
|
|
486
|
+
|
|
487
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 📄 License
|
|
492
|
+
|
|
493
|
+
MIT © Alam Jamal
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## 🔗 Links
|
|
498
|
+
|
|
499
|
+
- [GitHub Repository](https://github.com/alamjamal/wynkjs)
|
|
500
|
+
- [Issue Tracker](https://github.com/alamjamal/wynkjs/issues)
|
|
501
|
+
- [Elysia Documentation](https://elysiajs.com/)
|
|
502
|
+
- [TypeScript Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## 💖 Acknowledgments
|
|
507
|
+
|
|
508
|
+
Built with:
|
|
509
|
+
|
|
510
|
+
- [Elysia](https://elysiajs.com/) - The fast web framework
|
|
511
|
+
- [tsyringe](https://github.com/microsoft/tsyringe) - Dependency injection
|
|
512
|
+
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
<div align="center">
|
|
517
|
+
|
|
518
|
+
**[⬆ back to top](#-wynkjs)**
|
|
519
|
+
|
|
520
|
+
Made with ❤️ by [Alam Jamal](https://github.com/alamjamal)
|
|
521
|
+
|
|
522
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WynkJS Database Pattern - EXAMPLE ONLY
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ This file is NOT exported from WynkJS core.
|
|
5
|
+
* It's just an example pattern you can COPY to your project and customize.
|
|
6
|
+
*
|
|
7
|
+
* WHY NOT INCLUDED IN CORE?
|
|
8
|
+
* - Keeps WynkJS lightweight and fast (20x faster than NestJS!)
|
|
9
|
+
* - Gives you freedom to use ANY database library (Drizzle, Prisma, TypeORM, Mongoose, etc.)
|
|
10
|
+
* - No vendor lock-in
|
|
11
|
+
* - No unnecessary dependencies
|
|
12
|
+
*
|
|
13
|
+
* RECOMMENDED APPROACH:
|
|
14
|
+
* Use initializeDatabase() and getDatabase() from database.decorators.ts
|
|
15
|
+
* They're lightweight helpers already included in WynkJS core.
|
|
16
|
+
*
|
|
17
|
+
* BUT IF YOU PREFER A CLASS PATTERN, COPY THIS TO YOUR PROJECT:
|
|
18
|
+
*/
|
|
19
|
+
export declare const DATABASE_CLASS_EXAMPLE = "\n// src/db/database.ts (COPY THIS TO YOUR PROJECT)\n\nimport { Pool } from \"pg\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { userTable, otpTable } from '../users/tables';\n\nconst schema = { userTable, otpTable };\n\nexport class Database {\n private static instance: any;\n private static pool: Pool;\n\n public static getInstance() {\n if (!this.instance) {\n this.pool = new Pool({\n connectionString: process.env.DATABASE_URL!,\n max: 20,\n idleTimeoutMillis: 30000,\n connectionTimeoutMillis: 2000,\n ssl: { rejectUnauthorized: false },\n });\n\n this.instance = drizzle(this.pool, {\n schema,\n logger: true,\n });\n\n console.log(\"\u2705 Database connected\");\n }\n return this.instance;\n }\n\n public static async close() {\n if (this.pool) {\n await this.pool.end();\n this.instance = null;\n console.log(\"Database connection closed\");\n }\n }\n}\n\n// Usage in your index.ts:\n// import { Database } from './db/database';\n// const db = Database.getInstance();\n\n// Usage in your services:\n// import { Database } from '../db/database';\n// const db = Database.getInstance();\n// const users = await db.select().from(userTable);\n";
|
|
20
|
+
/**
|
|
21
|
+
* Example for other database libraries
|
|
22
|
+
*/
|
|
23
|
+
export declare const PRISMA_EXAMPLE = "\n// With Prisma (COPY TO YOUR PROJECT)\n\nimport { PrismaClient } from '@prisma/client';\n\nexport class Database {\n private static instance: PrismaClient;\n\n public static getInstance() {\n if (!this.instance) {\n this.instance = new PrismaClient();\n console.log(\"\u2705 Prisma connected\");\n }\n return this.instance;\n }\n\n public static async close() {\n if (this.instance) {\n await this.instance.$disconnect();\n console.log(\"Prisma disconnected\");\n }\n }\n}\n";
|
|
24
|
+
export declare const TYPEORM_EXAMPLE = "\n// With TypeORM (COPY TO YOUR PROJECT)\n\nimport { DataSource } from 'typeorm';\nimport { User, Post } from './entities';\n\nexport class Database {\n private static instance: DataSource;\n\n public static async getInstance() {\n if (!this.instance) {\n this.instance = new DataSource({\n type: 'postgres',\n url: process.env.DATABASE_URL,\n entities: [User, Post],\n synchronize: false,\n });\n await this.instance.initialize();\n console.log(\"\u2705 TypeORM connected\");\n }\n return this.instance;\n }\n\n public static async close() {\n if (this.instance?.isInitialized) {\n await this.instance.destroy();\n console.log(\"TypeORM disconnected\");\n }\n }\n}\n";
|
|
25
|
+
export declare const MONGOOSE_EXAMPLE = "\n// With Mongoose (COPY TO YOUR PROJECT)\n\nimport mongoose from 'mongoose';\n\nexport class Database {\n public static async connect() {\n if (mongoose.connection.readyState === 0) {\n await mongoose.connect(process.env.MONGODB_URL!, {\n maxPoolSize: 10,\n });\n console.log(\"\u2705 MongoDB connected\");\n }\n }\n\n public static async close() {\n await mongoose.connection.close();\n console.log(\"MongoDB disconnected\");\n }\n\n public static getConnection() {\n return mongoose.connection;\n }\n}\n";
|
|
26
|
+
/**
|
|
27
|
+
* README: How to use this file
|
|
28
|
+
*
|
|
29
|
+
* 1. Copy one of the examples above to your project (e.g., src/db/database.ts)
|
|
30
|
+
* 2. Customize it to your needs (connection string, pool config, etc.)
|
|
31
|
+
* 3. Import and use it in your services
|
|
32
|
+
*
|
|
33
|
+
* That's it! WynkJS doesn't force you to use any specific pattern.
|
|
34
|
+
* We give you the freedom to choose what works best for your project.
|
|
35
|
+
*/
|
|
36
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../core/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,sBAAsB,swCAkDlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,ygBAuB1B,CAAC;AAEF,eAAO,MAAM,eAAe,8uBA8B3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,0iBAwB5B,CAAC;AAEF;;;;;;;;;GASG"}
|