next-js-backend 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 +402 -0
- package/dist/docs/build.d.ts +2 -0
- package/dist/docs/dist/chunk-8whee738.d.ts +1 -0
- package/dist/docs/src/App.d.ts +2 -0
- package/dist/docs/src/components/MarkdownRenderer.d.ts +5 -0
- package/dist/docs/src/components/layout/DocsLayout.d.ts +1 -0
- package/dist/docs/src/components/ui/button.d.ts +10 -0
- package/dist/docs/src/components/ui/card.d.ts +9 -0
- package/dist/docs/src/components/ui/input.d.ts +3 -0
- package/dist/docs/src/components/ui/label.d.ts +4 -0
- package/dist/docs/src/components/ui/select.d.ts +15 -0
- package/dist/docs/src/components/ui/textarea.d.ts +3 -0
- package/dist/docs/src/frontend.d.ts +7 -0
- package/dist/docs/src/index.d.ts +1 -0
- package/dist/docs/src/lib/utils.d.ts +2 -0
- package/dist/docs/src/pages/DocsPages.d.ts +14 -0
- package/dist/docs/src/pages/index.d.ts +1 -0
- package/dist/docs/src/test/test-build.d.ts +1 -0
- package/dist/docs/src/test/test-mdx.d.ts +1 -0
- package/dist/docs/test-build.d.ts +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +61316 -0
- package/dist/samples/basic-crud/app.module.d.ts +2 -0
- package/dist/samples/basic-crud/index.d.ts +1 -0
- package/dist/samples/basic-crud/users.controller.d.ts +23 -0
- package/dist/samples/basic-crud/users.service.d.ts +18 -0
- package/dist/samples/class-validator-pipe/admins.controller.d.ts +12 -0
- package/dist/samples/class-validator-pipe/app.module.d.ts +2 -0
- package/dist/samples/class-validator-pipe/dto/create-admin.dto.d.ts +5 -0
- package/dist/samples/class-validator-pipe/index.d.ts +1 -0
- package/dist/samples/guards-interceptors/app.module.d.ts +2 -0
- package/dist/samples/guards-interceptors/auth.guard.d.ts +5 -0
- package/dist/samples/guards-interceptors/dashboard.controller.d.ts +11 -0
- package/dist/samples/guards-interceptors/index.d.ts +1 -0
- package/dist/samples/guards-interceptors/logging.interceptor.d.ts +5 -0
- package/dist/samples/swagger-openapi/app.module.d.ts +2 -0
- package/dist/samples/swagger-openapi/books.controller.d.ts +23 -0
- package/dist/samples/swagger-openapi/books.service.d.ts +18 -0
- package/dist/samples/swagger-openapi/index.d.ts +1 -0
- package/dist/src/auth/__tests__/password.service.test.d.ts +1 -0
- package/dist/src/auth/auth.guard.d.ts +8 -0
- package/dist/src/auth/index.d.ts +4 -0
- package/dist/src/auth/jwt.module.d.ts +10 -0
- package/dist/src/auth/jwt.service.d.ts +25 -0
- package/dist/src/auth/password.service.d.ts +32 -0
- package/dist/src/config/config.module.d.ts +10 -0
- package/dist/src/config/config.service.d.ts +25 -0
- package/dist/src/config/index.d.ts +2 -0
- package/dist/src/constants.d.ts +16 -0
- package/dist/src/decorators/catch.decorator.d.ts +10 -0
- package/dist/src/decorators/controller.decorator.d.ts +2 -0
- package/dist/src/decorators/filter.decorator.d.ts +7 -0
- package/dist/src/decorators/guard.decorator.d.ts +3 -0
- package/dist/src/decorators/interceptor.decorator.d.ts +3 -0
- package/dist/src/decorators/method.decorator.d.ts +19 -0
- package/dist/src/decorators/module.decorator.d.ts +16 -0
- package/dist/src/decorators/param.decorator.d.ts +37 -0
- package/dist/src/decorators/pipe.decorator.d.ts +3 -0
- package/dist/src/decorators/schema.decorator.d.ts +10 -0
- package/dist/src/di/__tests__/container.test.d.ts +1 -0
- package/dist/src/di/container.d.ts +23 -0
- package/dist/src/di/inject.decorator.d.ts +7 -0
- package/dist/src/di/injectable.decorator.d.ts +2 -0
- package/dist/src/di/provider.d.ts +20 -0
- package/dist/src/exceptions/http.exception.d.ts +13 -0
- package/dist/src/exceptions/index.d.ts +17 -0
- package/dist/src/exceptions/validation.pipe.d.ts +15 -0
- package/dist/src/factory/__tests__/exception-filters.test.d.ts +1 -0
- package/dist/src/factory/__tests__/file-upload.test.d.ts +1 -0
- package/dist/src/factory/elysia-factory.d.ts +26 -0
- package/dist/src/interfaces.d.ts +26 -0
- package/dist/src/services/logger.service.d.ts +39 -0
- package/dist/src/session/__tests__/session.module.test.d.ts +1 -0
- package/dist/src/session/session.module.d.ts +7 -0
- package/dist/src/session/session.options.d.ts +35 -0
- package/dist/src/session/session.service.d.ts +20 -0
- package/dist/src/session/session.store.d.ts +39 -0
- package/dist/test.d.ts +1 -0
- package/dist/testing/e2e/auth.test.d.ts +1 -0
- package/dist/testing/e2e/config.test.d.ts +1 -0
- package/dist/testing/e2e/di.test.d.ts +1 -0
- package/dist/testing/e2e/guards-interceptors.test.d.ts +1 -0
- package/dist/testing/e2e/routing.test.d.ts +1 -0
- package/dist/testing/e2e/validation.test.d.ts +1 -0
- package/index.ts +24 -0
- package/package.json +61 -0
- package/src/auth/__tests__/password.service.test.ts +38 -0
- package/src/auth/auth.guard.ts +34 -0
- package/src/auth/index.ts +4 -0
- package/src/auth/jwt.module.ts +24 -0
- package/src/auth/jwt.service.ts +65 -0
- package/src/auth/password.service.ts +48 -0
- package/src/config/config.module.ts +24 -0
- package/src/config/config.service.ts +78 -0
- package/src/config/index.ts +2 -0
- package/src/constants.ts +16 -0
- package/src/decorators/catch.decorator.ts +16 -0
- package/src/decorators/controller.decorator.ts +14 -0
- package/src/decorators/filter.decorator.ts +22 -0
- package/src/decorators/guard.decorator.ts +19 -0
- package/src/decorators/interceptor.decorator.ts +19 -0
- package/src/decorators/method.decorator.ts +37 -0
- package/src/decorators/module.decorator.ts +28 -0
- package/src/decorators/param.decorator.ts +80 -0
- package/src/decorators/pipe.decorator.ts +16 -0
- package/src/decorators/schema.decorator.ts +19 -0
- package/src/di/__tests__/container.test.ts +106 -0
- package/src/di/container.ts +98 -0
- package/src/di/inject.decorator.ts +14 -0
- package/src/di/injectable.decorator.ts +9 -0
- package/src/di/provider.ts +31 -0
- package/src/exceptions/http.exception.ts +29 -0
- package/src/exceptions/index.ts +32 -0
- package/src/exceptions/validation.pipe.ts +68 -0
- package/src/factory/__tests__/exception-filters.test.ts +102 -0
- package/src/factory/__tests__/file-upload.test.ts +70 -0
- package/src/factory/elysia-factory.ts +445 -0
- package/src/globals.d.ts +7 -0
- package/src/interfaces.ts +33 -0
- package/src/services/logger.service.ts +135 -0
- package/src/session/__tests__/session.module.test.ts +55 -0
- package/src/session/session.module.ts +43 -0
- package/src/session/session.options.ts +40 -0
- package/src/session/session.service.ts +47 -0
- package/src/session/session.store.ts +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tuan Nguyen
|
|
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,402 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/src/assets/logo.png" width="300" alt="Next.js Backend Logo" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Next.js Backend (Elysia Nest-like Library)
|
|
6
|
+
|
|
7
|
+
Một thư viện backend mạnh mẽ, tốc độ cao dành cho Node/Bun, được xây dựng trên nền tảng **ElysiaJS**. Nó mang kiến trúc **NestJS** quen thuộc và có tính cấu trúc cao (Decorators, Dependency Injection, Modules, Guards, Interceptors) đến với hệ sinh thái Elysia siêu tốc.
|
|
8
|
+
|
|
9
|
+
Được thiết kế tỉ mỉ để sẵn sàng cho **Serverless & Edge**, dễ dàng tích hợp trực tiếp vào Next.js App Router API endpoints thông qua `next-js-backend`.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🚀 Tính Năng (Features)
|
|
14
|
+
|
|
15
|
+
- **Kiến trúc giống NestJS**: Cấu trúc ứng dụng của bạn với `@Controller`, `@Injectable`, và `@Module`.
|
|
16
|
+
- **Lõi ElysiaJS**: Hoạt động dựa trên ElysiaJS và Bun, mang lại hiệu suất tối đa cùng với sự tích hợp TypeBox.
|
|
17
|
+
- **Dependency Injection**: Vùng chứa IoC siêu mạnh với đầy đủ tính năng, hỗ trợ `useClass`, `useValue`, `useFactory` và injection qua constructor tiêu chuẩn.
|
|
18
|
+
- **Quy trình xử lý (Pipeline)**:
|
|
19
|
+
- **Guards** (`@UseGuards`): Xác thực và phân quyền.
|
|
20
|
+
- **Interceptors** (`@UseInterceptors`): Ghi log request/response, thay đổi và biến đổi dữ liệu.
|
|
21
|
+
- **Pipes** (`@UsePipes`): Xác thực định dạng dữ liệu (hỗ trợ tích hợp sẵn `ValidationPipe` với `class-validator`).
|
|
22
|
+
- **Filters** (`@UseFilters`, `@Catch`): Quản lý luồng ngoại lệ (Custom Exception Handlers) toàn cục & theo cấp độ.
|
|
23
|
+
- **Quản lý Phiên (Session)**: Module `SessionModule` tích hợp sẵn dùng Cookie với hệ thống lưu trữ có thể cắm ghép (Redis/DB/Memory).
|
|
24
|
+
- **Core Modules**: Tích hợp sẵn `ConfigModule` (Xác thực tham số môi trường Env), `JwtModule` (Xác thực token) và `LoggerService`.
|
|
25
|
+
- **Next.js API Routes**: Tương thích tức thì theo dạng drop-in với `export const { GET, POST } = bootstrap()`.
|
|
26
|
+
- **Tải lên File (File Uploads)**: Hỗ trợ tự nhiên cho `@File()` / `@Files()` thông qua `multipart/form-data`.
|
|
27
|
+
- **OpenAPI / Swagger**: Hỗ trợ xuất sắc nhất thông qua các plugin gốc của Elysia.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 📦 Công Nghệ Sử Dụng (Tech Stack)
|
|
32
|
+
|
|
33
|
+
- **Runtime**: [Bun](https://bun.sh/)
|
|
34
|
+
- **Core Server**: [ElysiaJS](https://elysiajs.com/)
|
|
35
|
+
- **Validation**: [TypeBox](https://github.com/sinclairzx81/typebox) (Elysia gốc) & [class-validator](https://github.com/typestack/class-validator)
|
|
36
|
+
- **Metadata**: `reflect-metadata`
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🛠️ Bắt Đầu Cài Đặt (Getting Started)
|
|
41
|
+
|
|
42
|
+
### Cài đặt thư viện
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Clone repository hoặc chạy lệnh này trong dự án của bạn
|
|
46
|
+
bun install next-js-backend
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Chạy các Ứng Dụng Mẫu (Samples)
|
|
50
|
+
|
|
51
|
+
Chúng tôi cung cấp một số ứng dụng mẫu trong thư mục `samples/` để giúp bạn làm quen nhanh chóng:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Mô hình Controller & DI Cơ bản
|
|
55
|
+
bun run start:basic
|
|
56
|
+
|
|
57
|
+
# Xác thực định dạng DTO với class-validator
|
|
58
|
+
bun run start:validation
|
|
59
|
+
|
|
60
|
+
# Luồng Guards và Interceptors
|
|
61
|
+
bun run start:guards
|
|
62
|
+
|
|
63
|
+
# Tài liệu OpenAPI Swagger (Chạy trên cổng 3003)
|
|
64
|
+
bun run start:swagger
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 📖 Các Khái Niệm Cốt Lõi (Core Concepts)
|
|
70
|
+
|
|
71
|
+
### 1. Controllers & Routing
|
|
72
|
+
|
|
73
|
+
Controller có trách nhiệm nhận các request đổ về và trả response cho phía client. Sử dụng các khai báo (decorators) điều hướng định tuyến (`@Get`, `@Post`, v.v.) và khai báo trích xuất thông tin tham số (`@Body`, `@Param`, `@Query`, `@Headers`, `@Req`, `@Res`, `@Session`, `@File`, `@Files`) để lấy dữ liệu gửi lên một cách dễ dàng.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { Controller, Get, Post, Body, Param, Query, Headers } from "next-js-backend";
|
|
77
|
+
|
|
78
|
+
@Controller("/users")
|
|
79
|
+
export class UsersController {
|
|
80
|
+
@Get()
|
|
81
|
+
getAllUsers(@Query('role') role?: string) {
|
|
82
|
+
return [{ id: 1, name: "Alice", role: role || "user" }];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Get('/:id')
|
|
86
|
+
getUserById(@Param('id') userId: string, @Headers('authorization') token: string) {
|
|
87
|
+
return { id: userId, tokenProvided: !!token };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@Post()
|
|
91
|
+
createUser(@Body() body: any) {
|
|
92
|
+
return { success: true, data: body };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 2. Dependency Injection (Tiêm Phụ Thuộc - Services)
|
|
98
|
+
|
|
99
|
+
Hãy gắn nhãn `@Injectable()` vào các hàm Service để chúng có thể được inject (tiêm thông qua constructor) vào trong Controllers hoặc các service chức năng khác.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { Injectable, Controller, Get } from "next-js-backend";
|
|
103
|
+
|
|
104
|
+
@Injectable()
|
|
105
|
+
export class UsersService {
|
|
106
|
+
getUsers() {
|
|
107
|
+
return ["Alice", "Bob"];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Controller("/users")
|
|
112
|
+
export class UsersController {
|
|
113
|
+
constructor(private readonly usersService: UsersService) {}
|
|
114
|
+
|
|
115
|
+
@Get()
|
|
116
|
+
get() {
|
|
117
|
+
return this.usersService.getUsers();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 3. Pipeline Xác Thực (Validation)
|
|
123
|
+
|
|
124
|
+
Bạn có thể tự do tiến hành validation định dạng dữ liệu đầu vào sử dụng **TypeBox** (Cách gốc của Elysia) hoặc **class-validator** (Cách tiêu chuẩn của NestJS).
|
|
125
|
+
|
|
126
|
+
**Sử Dụng Class Validator (Định dạng DTO):**
|
|
127
|
+
|
|
128
|
+
````typescript
|
|
129
|
+
import { IsString, IsEmail } from "class-validator";
|
|
130
|
+
import { Body, Post, Controller, UsePipes, ValidationPipe } from "next-js-backend";
|
|
131
|
+
|
|
132
|
+
class CreateUserDto {
|
|
133
|
+
@IsString()
|
|
134
|
+
name: string;
|
|
135
|
+
|
|
136
|
+
@IsEmail()
|
|
137
|
+
email: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@Controller("/users")
|
|
141
|
+
export class UsersController {
|
|
142
|
+
@Post()
|
|
143
|
+
@UsePipes(new ValidationPipe())
|
|
144
|
+
create(@Body() dto: CreateUserDto) {
|
|
145
|
+
return dto;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 4. Guards & Interceptors
|
|
151
|
+
|
|
152
|
+
**Guards** sẽ quét và xác định xem Request có quyền được đi tiếp vào Route Handler (tức các Controller) hay bị bắt dừng lại.
|
|
153
|
+
**Interceptors** có thể gắn bổ sung logic ở trước / và sau sự kiện thực thi Route Methods.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { CanActivate, Context, NextInterceptor } from "next-js-backend";
|
|
157
|
+
|
|
158
|
+
export class AuthGuard implements CanActivate {
|
|
159
|
+
async canActivate(context: Context): Promise<boolean> {
|
|
160
|
+
const token = context.request.headers.get("authorization");
|
|
161
|
+
return token === "Bearer secret";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export class LoggingInterceptor implements NextInterceptor {
|
|
166
|
+
async intercept(context: Context, next: () => Promise<unknown>) {
|
|
167
|
+
console.log("Before execution...");
|
|
168
|
+
const result = await next();
|
|
169
|
+
console.log("After execution...");
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
````
|
|
174
|
+
|
|
175
|
+
Sử dụng các lớp này trực tiếp bằng các `@Use` (decorators):
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
@UseGuards(AuthGuard)
|
|
179
|
+
@UseInterceptors(LoggingInterceptor)
|
|
180
|
+
@Get('/secure')
|
|
181
|
+
getSecureData() { ... }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 5. Exception Filters (Xử Lý Lỗi)
|
|
185
|
+
|
|
186
|
+
Giành quyền làm chủ toàn diện vòng đời Lỗi / Response. Bắt các ngoại lệ `Error` đột xuất trực tiếp trên cấp bậc Route hoàn toàn giống hệt NextJS.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import {
|
|
190
|
+
Catch,
|
|
191
|
+
ExceptionFilter,
|
|
192
|
+
UseFilters,
|
|
193
|
+
Controller,
|
|
194
|
+
Get,
|
|
195
|
+
} from "next-js-backend";
|
|
196
|
+
|
|
197
|
+
class CustomError extends Error {}
|
|
198
|
+
|
|
199
|
+
@Catch(CustomError) // Catch only CustomError
|
|
200
|
+
export class MyExceptionFilter implements ExceptionFilter {
|
|
201
|
+
catch(exception: CustomError, context: any) {
|
|
202
|
+
context.set.status = 503;
|
|
203
|
+
return {
|
|
204
|
+
message: "Internal Logic Overridden",
|
|
205
|
+
errorDetails: exception.message,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@Controller("/users")
|
|
211
|
+
export class UsersController {
|
|
212
|
+
@Get()
|
|
213
|
+
@UseFilters(MyExceptionFilter)
|
|
214
|
+
crash() {
|
|
215
|
+
throw new CustomError("Oh no!");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 6. Bootstrapping & Tích Hợp Next.js App Router
|
|
221
|
+
|
|
222
|
+
Tổ hợp và gộp ứng dụng của bạn lại thông qua hệ thống `@Module` và khởi động (bootstrap) nó bằng hàm thư viện `ElysiaFactory`. Bạn có thể trích xuất ra một fetch handler tên là `app.handle` để gắn trực tiếp và chạy Native ngay lập tức trên các routes của Next.js Edge / API.
|
|
223
|
+
|
|
224
|
+
**Cho Môi trường Máy Chủ Độc Lập (Standalone JS Server):**
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { Module, ElysiaFactory } from "next-js-backend";
|
|
228
|
+
|
|
229
|
+
@Module({
|
|
230
|
+
controllers: [UsersController],
|
|
231
|
+
providers: [UsersService],
|
|
232
|
+
})
|
|
233
|
+
class AppModule {}
|
|
234
|
+
|
|
235
|
+
async function bootstrap() {
|
|
236
|
+
const app = await ElysiaFactory.create(AppModule);
|
|
237
|
+
app.listen(3000, () => {
|
|
238
|
+
console.log(`Server started on port 3000`);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
bootstrap();
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Cho Môi trường Next.js App Router (app/api/[...slug]/route.ts):**
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
import { ElysiaFactory } from "next-js-backend";
|
|
248
|
+
import { AppModule } from "./app.module";
|
|
249
|
+
|
|
250
|
+
// Hàm hỗ trợ "createNextJsHandlers" giải quyết tự động Singleton Pattern
|
|
251
|
+
// và tối ưu Cold-Start cho ứng dụng Next.js Edge/Serverless.
|
|
252
|
+
export const { GET, POST, PUT, PATCH, DELETE } =
|
|
253
|
+
ElysiaFactory.createNextJsHandlers(AppModule, {
|
|
254
|
+
globalPrefix: "/api",
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### 7. Các Module Tích Hợp Sẵn (Enterprise Features)
|
|
259
|
+
|
|
260
|
+
Thư viện này cung cấp sẵn cho bạn các Modules nội bộ, tiện lợi và vô cùng bảo mật để chạy nhanh dự án khi bootstrap ứng dụng:
|
|
261
|
+
|
|
262
|
+
**ConfigModule (Xác thực thông số môi trường - Environment):**
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { ConfigModule } from 'next-js-backend';
|
|
266
|
+
import { t } from 'elysia';
|
|
267
|
+
|
|
268
|
+
@Module({
|
|
269
|
+
imports: [
|
|
270
|
+
ConfigModule.forRoot({
|
|
271
|
+
isGlobal: true,
|
|
272
|
+
schema: t.Object({
|
|
273
|
+
DATABASE_URL: t.String(),
|
|
274
|
+
PORT: t.Numeric({ default: 3000 }),
|
|
275
|
+
JWT_SECRET: t.String()
|
|
276
|
+
})
|
|
277
|
+
})
|
|
278
|
+
]
|
|
279
|
+
})
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**JwtModule, AuthGuard & PasswordService (Mã hóa mật khẩu):**
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import {
|
|
286
|
+
JwtModule,
|
|
287
|
+
AuthGuard,
|
|
288
|
+
PasswordService,
|
|
289
|
+
UseGuards,
|
|
290
|
+
Controller,
|
|
291
|
+
Get,
|
|
292
|
+
} from "next-js-backend";
|
|
293
|
+
|
|
294
|
+
@Module({
|
|
295
|
+
imports: [JwtModule.register({ secret: "my-super-secret", expiresIn: "1h" })],
|
|
296
|
+
providers: [PasswordService],
|
|
297
|
+
})
|
|
298
|
+
class AuthModule {}
|
|
299
|
+
|
|
300
|
+
@Controller("/profile")
|
|
301
|
+
@UseGuards(AuthGuard)
|
|
302
|
+
export class ProfileController {
|
|
303
|
+
constructor(private password: PasswordService) {}
|
|
304
|
+
|
|
305
|
+
@Get("/me")
|
|
306
|
+
async getSecretData() {
|
|
307
|
+
const hash = await this.password.hash("mypassword", {
|
|
308
|
+
algorithm: "argon2id",
|
|
309
|
+
});
|
|
310
|
+
return { status: "Secure data", hash };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**SessionModule (Giải pháp lưu trữ Cookie bảo mật cao):**
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { SessionModule, Controller, Get, Session } from "next-js-backend";
|
|
319
|
+
|
|
320
|
+
@Module({
|
|
321
|
+
imports: [
|
|
322
|
+
SessionModule.register({
|
|
323
|
+
secret: "super-secret", // Signs the Cookie
|
|
324
|
+
cookieName: "sid",
|
|
325
|
+
ttl: 86400, // 1 day expiration
|
|
326
|
+
}),
|
|
327
|
+
],
|
|
328
|
+
})
|
|
329
|
+
class WebAppModule {}
|
|
330
|
+
|
|
331
|
+
@Controller("/profile")
|
|
332
|
+
export class ProfileController {
|
|
333
|
+
@Get("/me")
|
|
334
|
+
getProfile(@Session() session: SessionData) {
|
|
335
|
+
return session || { message: "Not logged in via cookie!" };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Built-in LoggerService (Ghi Log Hệ Thống):**
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { Logger } from "next-js-backend";
|
|
344
|
+
|
|
345
|
+
const logger = new Logger("MyContext");
|
|
346
|
+
logger.log("Standard log message");
|
|
347
|
+
logger.error("Error occurred", error.stack);
|
|
348
|
+
logger.warn("Warning log");
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## 🌍 Mở Rộng Type Toàn Cục (Global Type Augmentation)
|
|
352
|
+
|
|
353
|
+
Để lấy được tối đa sự an toàn Typescript (Type safety) khi sử dụng các phương pháp lấy biến động `@Session()` hay xử lý trong custom Guards, thư viện bóc tách các Types chuẩn bị sẵn (mở) Global interfaces cho bạn can thiệp từ `.d.ts` (ví dụ, chèn code vào file `globals.d.ts` hoặc `next-env.d.ts` của repository bạn).
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// types.d.ts
|
|
357
|
+
import "next-js-backend";
|
|
358
|
+
|
|
359
|
+
declare module "next-js-backend" {
|
|
360
|
+
interface SessionData {
|
|
361
|
+
userId: string;
|
|
362
|
+
role: "admin" | "user";
|
|
363
|
+
preferences: { theme: string };
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
interface User {
|
|
367
|
+
id: number;
|
|
368
|
+
email: string;
|
|
369
|
+
isActive: boolean;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Và giờ đây, bất kì lúc nào bạn tiến hành dùng decorater `@Session() session`, Trình soạn thảo IDE của bạn đều sẽ gợi ý lệnh (auto-complete) rất hoàn hảo như thuộc tính `session.role` hay `session.userId`!
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## 🧪 Testing (Chạy Thử Nghiệm)
|
|
379
|
+
|
|
380
|
+
Chúng tôi sử dụng môi trường test trực tiếp thông qua runner của Bun (`bun:test`). Tất cả files cấu hình bài test nghiệm thu thư mục nguồn (source) đều chứa bên trong thư mục `__tests__` đi liền cạnh.
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
bun test
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## 💖 Lời Cảm Ơn (Acknowledgements)
|
|
389
|
+
|
|
390
|
+
Đặc biệt gửi lời cảm ơn tới **Antigravity** (Google DeepMind) đã đồng hành, hỗ trợ kỹ thuật và giúp tôi hiện thực hóa toàn bộ ý tưởng của Thư viện này từ những dòng code đầu tiên. Cùng với sức mạnh của tinh thần pair-programming, **Next.js Backend** đã ra đời!
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## 📜 Giấy Phép (License)
|
|
395
|
+
|
|
396
|
+
**MIT License**
|
|
397
|
+
|
|
398
|
+
Copyright (c) 2026 Tuan Nguyen
|
|
399
|
+
|
|
400
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
401
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
402
|
+
in the Software without restriction, including without limitation the rights
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function DocsLayout(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
|
+
size?: "default" | "icon" | "sm" | "lg" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
declare function Card({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
declare function CardHeader({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function CardTitle({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function CardDescription({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare function CardAction({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare function CardContent({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare function CardFooter({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare function SelectTrigger({ className, size, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
7
|
+
size?: "sm" | "default";
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
declare function SelectContent({ className, children, position, align, ...props }: React.ComponentProps<typeof SelectPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
declare function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
declare function SelectScrollDownButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function IntroPage(): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function FirstStepsPage(): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export declare function NextjsIntegrationPage(): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function ControllersPage(): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function ProvidersPage(): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function ModulesPage(): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function GuardsPage(): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function InterceptorsPage(): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function PipesPage(): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function ExceptionsPage(): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function OpenAPIPage(): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function LoggerPage(): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function ConfigModulePage(): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function JwtAuthPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { IntroPage, FirstStepsPage, NextjsIntegrationPage, ControllersPage, ProvidersPage, ModulesPage, GuardsPage, InterceptorsPage, PipesPage, ExceptionsPage, OpenAPIPage, LoggerPage, ConfigModulePage, JwtAuthPage } from './DocsPages';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export * from './src/constants';
|
|
2
|
+
export * from './src/interfaces';
|
|
3
|
+
export * from './src/decorators/controller.decorator';
|
|
4
|
+
export { Get, Post, Put, Delete, Patch, Options, Head, All, RequestMethod } from './src/decorators/method.decorator';
|
|
5
|
+
export * from './src/decorators/module.decorator';
|
|
6
|
+
export * from './src/decorators/param.decorator';
|
|
7
|
+
export * from './src/decorators/schema.decorator';
|
|
8
|
+
export * from './src/decorators/guard.decorator';
|
|
9
|
+
export * from './src/decorators/interceptor.decorator';
|
|
10
|
+
export * from './src/decorators/pipe.decorator';
|
|
11
|
+
export * from './src/decorators/catch.decorator';
|
|
12
|
+
export * from './src/decorators/filter.decorator';
|
|
13
|
+
export * from './src/di/injectable.decorator';
|
|
14
|
+
export * from './src/di/container';
|
|
15
|
+
export * from './src/exceptions';
|
|
16
|
+
export * from './src/exceptions/validation.pipe';
|
|
17
|
+
export * from './src/factory/elysia-factory';
|
|
18
|
+
export * from './src/services/logger.service';
|
|
19
|
+
export * from './src/config/config.service';
|
|
20
|
+
export * from './src/config/config.module';
|
|
21
|
+
export * from './src/auth';
|
|
22
|
+
export * from './src/session/session.module';
|
|
23
|
+
export * from './src/session/session.service';
|
|
24
|
+
export * from './src/session/session.store';
|
|
25
|
+
export * from './src/session/session.options';
|