@gennext/lb-infra 0.2.1 → 0.2.3

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.
Files changed (78) hide show
  1. package/README.md +181 -223
  2. package/dist/base/applications/base.application.d.ts +12 -21
  3. package/dist/base/applications/base.application.d.ts.map +1 -1
  4. package/dist/base/applications/base.application.js +25 -27
  5. package/dist/base/applications/base.application.js.map +1 -1
  6. package/dist/base/hono/hono-adapter.d.ts +10 -0
  7. package/dist/base/hono/hono-adapter.d.ts.map +1 -0
  8. package/dist/base/hono/hono-adapter.js +27 -0
  9. package/dist/base/hono/hono-adapter.js.map +1 -0
  10. package/dist/base/index.js +1 -1
  11. package/dist/base/index.js.map +1 -1
  12. package/dist/base/models/base.model.d.ts +2 -1
  13. package/dist/base/models/base.model.d.ts.map +1 -1
  14. package/dist/base/models/base.model.js +2 -1
  15. package/dist/base/models/base.model.js.map +1 -1
  16. package/dist/base/models/column-defs.d.ts +2 -2
  17. package/dist/base/models/decorators.d.ts +15 -0
  18. package/dist/base/models/decorators.d.ts.map +1 -0
  19. package/dist/base/models/decorators.js +19 -0
  20. package/dist/base/models/decorators.js.map +1 -0
  21. package/dist/base/models/index.d.ts +2 -0
  22. package/dist/base/models/index.d.ts.map +1 -1
  23. package/dist/base/models/index.js +2 -0
  24. package/dist/base/models/index.js.map +1 -1
  25. package/dist/base/models/model.helper.d.ts +7 -0
  26. package/dist/base/models/model.helper.d.ts.map +1 -0
  27. package/dist/base/models/model.helper.js +16 -0
  28. package/dist/base/models/model.helper.js.map +1 -0
  29. package/dist/base/repository/default-crud.repository.d.ts +3 -3
  30. package/dist/base/repository/default-crud.repository.d.ts.map +1 -1
  31. package/dist/base/repository/default-crud.repository.js +20 -17
  32. package/dist/base/repository/default-crud.repository.js.map +1 -1
  33. package/dist/base/repository/filter.builder.d.ts +7 -0
  34. package/dist/base/repository/filter.builder.d.ts.map +1 -0
  35. package/dist/base/repository/filter.builder.js +74 -0
  36. package/dist/base/repository/filter.builder.js.map +1 -0
  37. package/dist/base/repository/readable.repository.d.ts +10 -8
  38. package/dist/base/repository/readable.repository.d.ts.map +1 -1
  39. package/dist/base/repository/readable.repository.js +26 -19
  40. package/dist/base/repository/readable.repository.js.map +1 -1
  41. package/dist/base/repository/soft-deletable.repository.d.ts +3 -2
  42. package/dist/base/repository/soft-deletable.repository.d.ts.map +1 -1
  43. package/dist/base/repository/soft-deletable.repository.js +26 -15
  44. package/dist/base/repository/soft-deletable.repository.js.map +1 -1
  45. package/dist/boot/base/base-artifact-booter.d.ts +3 -0
  46. package/dist/boot/base/base-artifact-booter.d.ts.map +1 -1
  47. package/dist/boot/base/base-artifact-booter.js +3 -0
  48. package/dist/boot/base/base-artifact-booter.js.map +1 -1
  49. package/dist/boot/boot.mixin.d.ts.map +1 -1
  50. package/dist/boot/boot.mixin.js +10 -4
  51. package/dist/boot/boot.mixin.js.map +1 -1
  52. package/dist/boot/booters/controller.booter.d.ts.map +1 -1
  53. package/dist/boot/booters/controller.booter.js +5 -1
  54. package/dist/boot/booters/controller.booter.js.map +1 -1
  55. package/dist/common/constants.d.ts +2 -0
  56. package/dist/common/constants.d.ts.map +1 -1
  57. package/dist/common/constants.js +2 -0
  58. package/dist/common/constants.js.map +1 -1
  59. package/dist/helpers/logger/config.d.ts.map +1 -1
  60. package/dist/helpers/logger/config.js +1 -2
  61. package/dist/helpers/logger/config.js.map +1 -1
  62. package/dist/index.d.ts +1 -1
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +2 -2
  65. package/dist/index.js.map +1 -1
  66. package/dist/utilities/migration.utility.d.ts +13 -0
  67. package/dist/utilities/migration.utility.d.ts.map +1 -1
  68. package/dist/utilities/migration.utility.js +39 -0
  69. package/dist/utilities/migration.utility.js.map +1 -1
  70. package/package.json +9 -1
  71. package/dist/base/loopback/filter/index.d.ts +0 -2
  72. package/dist/base/loopback/filter/index.d.ts.map +0 -1
  73. package/dist/base/loopback/filter/index.js +0 -5
  74. package/dist/base/loopback/filter/index.js.map +0 -1
  75. package/dist/base/loopback/http-server/index.d.ts +0 -2
  76. package/dist/base/loopback/http-server/index.d.ts.map +0 -1
  77. package/dist/base/loopback/http-server/index.js +0 -5
  78. package/dist/base/loopback/http-server/index.js.map +0 -1
package/README.md CHANGED
@@ -1,310 +1,261 @@
1
- # @gennext/lb-infra
1
+ # 📘 Cẩm nang Kĩ thuật: @gennext/lb-infra
2
2
 
3
- Hệ thống thư viện hạ tầng (infrastructure) backend dựa trên TypeScript, tối ưu cho hiệu năng tính chuẩn hóa.
4
-
5
- ## 1. Giới thiệu
6
- `@gennext/lb-infra` là nền tảng xây dựng backend hiện đại tại Gennex, kết hợp các công nghệ:
7
- - **Hono**: Web framework siêu nhẹ, hỗ trợ TypeScript và OpenAPI native.
8
- - **Drizzle ORM**: ORM thế hệ mới, type-safe tuyệt đối cho PostgreSQL.
9
- - **Zod**: Thư viện validation và định nghĩa schema mạnh mẽ.
10
- - **Winston**: Hệ thống logging đa kênh (Console, File, UDP).
11
-
12
- **Khi nào nên dùng:** Phù hợp cho các dự án yêu cầu tốc độ phản hồi cao, cấu trúc mã nguồn tường minh (Controller-Service-Repository) và tự động hóa tài liệu API (Swagger/OpenAPI).
3
+ Hạ tầng Backend Hybrid chuẩn Gennex: Kết hợp sức mạnh kiến trúc của **LoopBack 4** và hiệu năng của **Hono/Drizzle**.
13
4
 
14
5
  ---
15
6
 
16
- ## 2. Cài đặt
7
+ ## 🏗 1. Tổng quan kiến trúc & Cài đặt
17
8
 
18
- Cài đặt package chính:
19
- ```bash
20
- bun add @gennext/lb-infra
21
- ```
9
+ ### 1.1 Hybrid Platform
22
10
 
23
- Các peer dependency cần thiết:
24
- ```bash
25
- bun add hono @hono/zod-openapi zod drizzle-orm pg winston
26
- # Nếu dùng Auth/Authorization
27
- bun add jose casbin
28
- ```
11
+ Thư viện cung cấp hai lộ trình phát triển:
29
12
 
30
- ---
13
+ - **Hono Path (Modern):** Cho các service yêu cầu tốc độ cao, hỗ trợ OpenAPI native qua Zod.
14
+ - **LoopBack Path (Standard):** Cho các ứng dụng phức tạp cần DI (Dependency Injection) và tính tương thích ngược.
31
15
 
32
- ## 3. Khởi tạo ứng dụng
33
- Sử dụng `BaseApplication` kết hợp với `bootMixin` để tự động quét và đăng ký các thành phần.
16
+ ### 1.2 Cấu trúc Export (Sub-paths)
34
17
 
35
- ```typescript
36
- import { BaseApplication, bootMixin, bootStrapApplication, IApplicationConfigs } from '@gennext/lb-infra';
18
+ Được cấu hình trong `package.json`, giúp developer import sạch sẽ:
37
19
 
38
- class OrderApplication extends bootMixin(BaseApplication) {
39
- getAppInfo() {
40
- return {
41
- name: 'Order Service',
42
- version: '1.0.0',
43
- };
44
- }
45
- }
20
+ - `@gennext/lb-infra`: Entry chính (Hono, Drizzle, Utilities).
21
+ - `@gennext/lb-infra/lb-core`: LoopBack Core (Binding, Context, Metadata).
22
+ - `@gennext/lb-infra/lb-rest`: LoopBack Rest (Decorators, Sequence).
23
+ - `@gennext/lb-infra/lb-repo`: LoopBack Repository (Juggler, Filter).
24
+ - `@gennext/lb-infra/socket-io`: WebSocket component.
25
+ - `@gennext/lb-infra/grpc`: gRPC component.
46
26
 
47
- const configs: IApplicationConfigs = {
48
- port: Number(process.env.PORT) || 3000,
49
- path: { base: '/api' }
50
- };
27
+ ### 1.3 Pin Dependencies (Không cần cài thêm)
51
28
 
52
- bootStrapApplication(OrderApplication, configs);
53
- ```
29
+ Thư viện đã đóng gói sẵn và re-export các "vũ khí" sau:
30
+
31
+ - **Framework:** `Hono`, `@hono/zod-openapi`, `zod`.
32
+ - **Database:** `Drizzle ORM` (core + pg), `pg` (node-postgres).
33
+ - **Utilities:** `axios`, `lodash`, `dayjs` (thông qua `date.utility`).
54
34
 
55
35
  ---
56
36
 
57
- ## 4. Data layer
58
- Sử dụng Drizzle để định nghĩa schema và các Repository để thao tác dữ liệu.
37
+ ## 🚀 2. Application Kernel
59
38
 
60
- ### Khai báo Drizzle Schema
61
- Sử dụng các helper trong `column-defs.ts` để chuẩn hóa cấu trúc bảng.
39
+ ### 2.1 Khởi tạo với `BaseApplication`
62
40
 
63
- ```typescript
64
- import { pgTable, text, integer } from 'drizzle-orm/pg-core';
65
- import { generateIdColumnDefs, generateSoftDeleteColumnDefs, generateTzColumnDefs } from '@gennext/lb-infra';
41
+ Mọi ứng dụng phải kế thừa từ class này.
66
42
 
67
- export const orders = pgTable('orders', {
68
- ...generateIdColumnDefs({ id: { dataType: 'string' } }),
69
- orderNumber: text('order_number').notNull(),
70
- amount: integer('amount'),
71
- ...generateTzColumnDefs(),
72
- ...generateSoftDeleteColumnDefs(),
73
- });
74
- ```
43
+ **Interface `IApplicationConfigs`:**
75
44
 
76
- ### Repositories
77
- Sử dụng `DefaultCrudRepository` hoặc `SoftDeletableRepository` để có sẵn các hàm CRUD.
45
+ - `port`: (Bắt buộc) Cổng chạy server.
46
+ - `host?`: Hostname (Mặc định `0.0.0.0`).
47
+ - `path?`: `{ base: string, isStrict?: boolean }` - Prefix cho API.
48
+ - `debug?`: `{ shouldShowRoutes?: boolean }` - In ra danh sách route khi startup.
78
49
 
79
- ```typescript
80
- import { SoftDeletableRepository } from '@gennext/lb-infra';
81
- import { orders } from '../models/order.schema';
50
+ **Vòng đời (Lifecycle) trong `start()`:**
82
51
 
83
- export class OrderRepository extends SoftDeletableRepository<typeof orders> {
84
- constructor() {
85
- super(orders);
86
- }
87
- }
88
- ```
52
+ 1. `preConfigure()`: Thiết lập biến môi trường, kết nối DB sớm.
53
+ 2. `setupMiddlewares()`: Đăng ký Logger, CORS, v.v.
54
+ 3. `boot()`: Tự động đăng ký Controllers/Services (khi dùng `bootMixin`).
55
+ 4. `postConfigure()`: Chạy các tác vụ sau khi server đã lắng nghe.
89
56
 
90
- ---
57
+ ### 2.2 Dependency Injection (DI)
91
58
 
92
- ## 5. Service layer
93
- Các service kế thừa `BaseService` và sử dụng `this.logger` (HFLogger pattern) để ghi log theo phương thức.
59
+ Hệ thống sử dụng Map-based Binding:
94
60
 
95
- ```typescript
96
- import { BaseService } from '@gennext/lb-infra';
97
-
98
- export class OrderService extends BaseService {
99
- async processOrder(orderId: string) {
100
- const logger = this.logger.for('processOrder');
101
- logger.info('Starting process', { orderId });
102
-
103
- try {
104
- // Logic xử lý đơn hàng...
105
- } catch (error) {
106
- logger.error('Failed to process', error);
107
- throw error;
108
- }
109
- }
110
- }
111
- ```
61
+ - **Bind:** `app.bind({ key: 'services.UserService' }).toClass(UserService)`
62
+ - **Get:** `const service = app.get<UserService>({ key: 'services.UserService' })`
63
+ - **Namespaces:** Nên dùng `BindingNamespaces.SERVICE`, `.CONTROLLER`, `.REPOSITORY`, `.DATASOURCE`.
112
64
 
113
65
  ---
114
66
 
115
- ## 6. Controller & Routing
116
- Controller quản lý các route và tích hợp Zod để tự động tạo tài liệu OpenAPI qua `defineRoute` hoặc `bindRoute`.
67
+ ## 🪵 3. Hệ thống Logger & Context
117
68
 
118
- ```typescript
119
- import { BaseController, controller } from '@gennext/lb-infra';
120
- import { z } from 'zod';
69
+ ### 3.1 Logger nâng cao
121
70
 
122
- const OrderSchema = z.object({
123
- id: z.string().uuid(),
124
- amount: z.number().min(1)
125
- });
71
+ Được xây dựng trên Winston, hỗ trợ ghi log đa kênh.
126
72
 
127
- @controller({ path: '/orders' })
128
- export class OrderController extends BaseController {
129
- async binding() {
130
- this.bindRoute({
131
- configs: {
132
- path: '/',
133
- method: 'post',
134
- request: {
135
- body: { content: { 'application/json': { schema: OrderSchema } } }
136
- },
137
- responses: {
138
- 200: {
139
- description: 'Order created',
140
- content: { 'application/json': { schema: OrderSchema } }
141
- }
142
- }
143
- }
144
- }).to({
145
- handler: async (c) => {
146
- const body = await c.req.json();
147
- return c.json(body);
148
- }
149
- });
150
- }
151
- }
152
- ```
73
+ **Các Method:**
153
74
 
154
- ---
75
+ - `debug(msg, ...args)`: ⚠️ Chỉ hoạt động nếu `NODE_ENV` là local/dev/alpha... **VÀ** biến `DEBUG=true`.
76
+ - `withScope(scope)`: Gắn prefix cho log.
77
+ - `for(method)`: Child logger cho từng hàm cụ thể (có cache để tối ưu).
155
78
 
156
- ## 7. DataSources
157
- Cấu hình kết nối sở dữ liệu qua các class kế thừa.
79
+ **UDP Logging (`DgramTransport`):**
80
+ Gửi log qua socket UDP (ví dụ đến Logstash/Graylog).
81
+ Cấu hình qua `IDgramTransportOptions`: `host`, `port`, `levels` (các mức log muốn gửi đi).
158
82
 
159
- ```typescript
160
- import { PostgresDataSource, RedisDataSource } from '@gennext/lb-infra/datasources';
83
+ ### 3.2 RequestContext & HttpAccessLogger
161
84
 
162
- export class DbDataSource extends PostgresDataSource {
163
- static dataSourceName = 'db';
164
- }
85
+ Dùng để theo vết request ID xuyên suốt các tầng.
165
86
 
166
- export class CacheDataSource extends RedisDataSource {
167
- static dataSourceName = 'redis';
168
- }
169
- ```
87
+ - **Tự động hóa:** Middleware tự lấy `x-request-id` từ header hoặc tự sinh mới.
88
+ - **Data Masking:** Tự động ẩn thông tin nhạy cảm trong log: `authorization`, `cookie`, `session`, `password`.
170
89
 
171
90
  ---
172
91
 
173
- ## 8. Logger helper
174
- Hệ thống log mạnh mẽ hỗ trợ `RequestContext` để theo vết Request ID xuyên suốt các layer.
92
+ ## 🗄️ 4. Data Layer (Drizzle ORM)
175
93
 
176
- ```typescript
177
- import { LoggerFactory, RequestContext } from '@gennext/lb-infra';
94
+ ### 4.1 Schema Helpers (`column-defs.ts`)
178
95
 
179
- const logger = LoggerFactory.getLogger(['OrderModule']);
96
+ Giúp định nghĩa bảng chuẩn Gennex:
180
97
 
181
- // Sử dụng RequestContext để gắn ID tự động
182
- RequestContext.run({ requestId: 'req-123' }, () => {
183
- logger.info('User action log'); // Log sẽ có prefix [req-123]
184
- });
185
- ```
98
+ - `generateIdColumnDefs()`: Cột `id` (Serial hoặc UUID).
99
+ - `generateTzColumnDefs()`: Cột `created_at`, `modified_at` tự động cập nhật.
100
+ - `generateSoftDeleteColumnDefs()`: Cột `deleted_at`.
186
101
 
187
- ---
102
+ ### 4.2 Tầng Repository (Tiering)
188
103
 
189
- ## 9. Redis helper
190
- Bộ công cụ hỗ trợ Redis String, Hash, JSON và Pub/Sub.
104
+ - **ReadableRepository**: Tìm kiếm cơ bản.
105
+ - **DefaultCRUDRepository**: Thao tác Thêm/Sửa/Xóa.
106
+ - **SoftDeletableRepository**: 💡 Tự động thêm điều kiện `deleted_at IS NULL` vào mọi câu query.
107
+ - `hardDeleteById()`: Xóa vĩnh viễn.
108
+ - `restore()`: Khôi phục bản ghi đã xóa.
191
109
 
192
- ```typescript
193
- import { RedisHelper } from '@gennext/lb-infra/helpers/redis';
110
+ ---
194
111
 
195
- const redis = new RedisHelper({ host: 'localhost', port: 6379 });
112
+ ## 5. Redis & Caching
196
113
 
197
- await redis.set({ key: 'config', value: { theme: 'dark' } });
114
+ ### 5.1 RedisManager
198
115
 
199
- // Thao tác với RedisJSON
200
- await redis.jSet({
201
- key: 'user:data',
202
- path: '$',
203
- value: { settings: { lang: 'vi' } }
204
- });
116
+ Quản tập trung các instance Redis. Hỗ trợ cả **Standalone** và **Cluster mode**.
205
117
 
206
- const lang = await redis.jGet({ key: 'user:data', path: '$.settings.lang' });
207
- ```
118
+ ### 5.2 DefaultRedisHelper API
119
+
120
+ - `set({ key, value, options: { ttl } })`: Lưu object (tự serialize JSON).
121
+ - `getObject({ key })`: Lấy và tự parse JSON.
122
+ - `publish({ topics, payload, useCompress })`: Pub/Sub có hỗ trợ nén zlib để tiết kiệm băng thông.
208
123
 
209
124
  ---
210
125
 
211
- ## 10. Authentication
212
- Tích hợp sẵn các chiến lược xác thực phổ biến.
126
+ ## 🌐 6. HTTP Layer (Hono + OpenAPI)
213
127
 
214
- ```typescript
215
- import { AuthenticateComponent, JwtStrategy } from '@gennext/lb-infra';
128
+ ### 6.1 BaseController
129
+
130
+ Sử dụng `bindRoute` để có được sự hỗ trợ tuyệt đối từ TypeScript và tự sinh Swagger.
216
131
 
217
- // Trong BaseApplication
218
- this.component(AuthenticateComponent);
219
- this.bind('authentication.strategies.jwt').toClass(JwtStrategy);
132
+ ```typescript
133
+ this.bindRoute({
134
+ configs: {
135
+ path: '/:id',
136
+ method: 'get',
137
+ request: { params: zod.object({ id: zod.string() }) },
138
+ responses: { 200: jsonResponse({ schema: UserSchema, description: 'User info' }) },
139
+ },
140
+ }).to({
141
+ handler: async c => {
142
+ const id = c.req.param('id');
143
+ // ... logic
144
+ },
145
+ });
220
146
  ```
221
147
 
222
148
  ---
223
149
 
224
- ## 11. Authorization
225
- Phân quyền dựa trên thuộc tính (RBAC/ABAC) sử dụng Casbin.
226
-
227
- ```typescript
228
- import { AuthorizeComponent, DrizzleCasbinAdapter } from '@gennext/lb-infra';
150
+ ## 🧰 7. Bộ tiện ích (Utilities Deep Dive)
229
151
 
230
- this.component(AuthorizeComponent);
231
- // Dùng DrizzleCasbinAdapter để lưu policy vào PostgreSQL
232
- ```
152
+ | Utility | Method tiêu biểu | Mô tả |
153
+ | :---------- | :-------------------------------------------------------------- | :------------------------------------ |
154
+ | **parse** | `getUID()`, `keysToCamel()`, `toBoolean()`, `int()`, `float()` | Xử lý kiểu dữ liệu và format key. |
155
+ | **crypto** | `hashPassword()`, `comparePassword()`, `encrypt()`, `decrypt()` | Bảo mật mật khẩu và mã hóa AES. |
156
+ | **error** | `getError()`, `ValidationError()`, `NotImplementedError()` | Tạo lỗi chuẩn hóa có Status Code. |
157
+ | **model** | `buildRequestBody()`, `buildPaginationResponse()` | Tự động sinh OpenAPI schema từ Model. |
158
+ | **promise** | `delay(ms)` | Hàm ngủ async. |
159
+ | **axios** | `get()`, `post()`, `put()`, `del()` | Wrapper axios kèm xử lý lỗi chuẩn. |
233
160
 
234
161
  ---
235
162
 
236
- ## 12. Components tùy chọn
163
+ ## 🔑 8. Auth & Security
237
164
 
238
- ### gRPC
239
- ```typescript
240
- import { BaseGrpcController } from '@gennext/lb-infra/components/grpc';
165
+ ### 8.1 Authentication
241
166
 
242
- export class UserGrpcController extends BaseGrpcController {
243
- // Implement gRPC methods defined in proto
244
- }
245
- ```
167
+ - Đăng `AuthenticateComponent`.
168
+ - Hỗ trợ `JwtStrategy` (đọc secret từ `APP_ENV_APPLICATION_SECRET`).
169
+
170
+ ### 8.2 Authorization (Casbin)
246
171
 
247
- ### Socket.IO
248
- Sử dụng `SocketIOServerHelper` để quản lý kết nối thời gian thực.
172
+ ⚠️ Cần cài `casbin`.
249
173
 
250
- ### Health Check
251
- Tích hợp sẵn endpoint `/health` để monitor trạng thái hệ thống.
174
+ - `CasbinDrizzleAdapter`: Lưu Policy vào bảng DB do Drizzle quản lý.
175
+ - `CasbinEnforcer`: Check quyền bằng pháp: `enforcer.enforce(user, object, action)`.
252
176
 
253
177
  ---
254
178
 
255
- ## 13. Utilities
256
- Các hàm tiện ích tối ưu trong `src/utilities`:
179
+ ## 🧪 9. Ví dụ: Full User Flow
180
+
181
+ ```typescript
182
+ // --- 1. Model ---
183
+ export const users = pgTable('users', {
184
+ ...generateIdColumnDefs({ id: { dataType: 'string' } }),
185
+ email: text('email').notNull().unique(),
186
+ ...generateTzColumnDefs(),
187
+ ...generateSoftDeleteColumnDefs(),
188
+ });
189
+
190
+ // --- 2. Repository ---
191
+ export class UserRepository extends SoftDeletableRepository<typeof users> {
192
+ constructor() {
193
+ super(users);
194
+ }
195
+ }
257
196
 
258
- - `getError(opts)`: Tạo error object chuẩn kèm `statusCode`.
259
- - `hash(text, opts)`: Hỗ trợ MD5, SHA256...
260
- - `safeParseJson(str)`: Parse JSON không lo crash.
261
- - `executePromiseWithLimit({ tasks, limit })`: Chạy batch tasks có giới hạn số lượng chạy song song.
262
- - `getDateTz()`: Lấy thời gian hiện tại theo múi giờ cấu hình.
263
- - `buildBatchUpdateQuery(table, data)`: Helper tạo câu lệnh cập nhật hàng loạt cho Drizzle.
197
+ // --- 3. Controller ---
198
+ @controller({ path: '/users' })
199
+ export class UserController extends BaseController {
200
+ async binding() {
201
+ this.bindRoute({
202
+ configs: {
203
+ path: '/',
204
+ method: 'get',
205
+ responses: { 200: { description: 'List' } },
206
+ },
207
+ }).to({
208
+ handler: async c => {
209
+ const repo = app.get<UserRepository>({ key: 'repositories.UserRepository' });
210
+ return c.json(await repo.findAll());
211
+ },
212
+ });
213
+ }
214
+ }
215
+ ```
264
216
 
265
217
  ---
266
218
 
267
- ## 14. Base classes
219
+ ## 🛠️ 10. Scripts
268
220
 
269
- | Class | Thuộc tính/Phương thức sẵn |
270
- | :--- | :--- |
271
- | `BaseHelper` | `this.logger` |
272
- | `BaseService` | `this.logger` (HFLogger), `this.get(key)` (DI) |
273
- | `BaseController` | `this.logger`, `this.bindRoute()`, `this.defineRoute()` |
274
- | `BaseDataSource` | `this.name`, `this.connector` |
221
+ - `bun run build`: Build project (TSC + tsc-alias).
222
+ - `bun run migrate:push`: Đẩy schema Drizzle lên Database.
223
+ - `bun run lint`: Kiểm tra code style các file mới thay đổi.
275
224
 
276
225
  ---
277
226
 
278
- ## 15. Biến môi trường
279
-
280
- | Tên biến | Mô tả | Giá trị mặc định |
281
- | :--- | :--- | :--- |
282
- | `APP_ENV_APPLICATION_NAME` | Tên ứng dụng xuất hiện trong log | `APP` |
283
- | `APP_ENV_POSTGRES_HOST` | Địa chỉ PostgreSQL | `localhost` |
284
- | `APP_ENV_POSTGRES_PORT` | Cổng PostgreSQL | `5432` |
285
- | `APP_ENV_POSTGRES_USERNAME` | Username DB | `postgres` |
286
- | `APP_ENV_POSTGRES_PASSWORD` | Password DB | `password` |
287
- | `APP_ENV_POSTGRES_DATABASE` | Tên Database | `postgres` |
288
- | `APP_ENV_REDIS_DATASOURCE_HOST` | Địa chỉ Redis | `0.0.0.0` |
289
- | `APP_ENV_REDIS_DATASOURCE_PORT` | Cổng Redis | `6379` |
290
- | `APP_ENV_LOGGER_FOLDER_PATH` | Đường dẫn lưu file log | `./logs` |
291
- | `DEBUG` | Kích hoạt log debug | `false` |
227
+ ## 11. Biến môi trường
228
+
229
+ | Tên biến | Mô tả | Giá trị mặc định |
230
+ | :------------------------------ | :------------------------------- | :--------------- |
231
+ | `APP_ENV_APPLICATION_NAME` | Tên ứng dụng xuất hiện trong log | `APP` |
232
+ | `APP_ENV_POSTGRES_HOST` | Địa chỉ PostgreSQL | `localhost` |
233
+ | `APP_ENV_POSTGRES_PORT` | Cổng PostgreSQL | `5432` |
234
+ | `APP_ENV_POSTGRES_USERNAME` | Username DB | `postgres` |
235
+ | `APP_ENV_POSTGRES_PASSWORD` | Password DB | `password` |
236
+ | `APP_ENV_POSTGRES_DATABASE` | Tên Database | `postgres` |
237
+ | `APP_ENV_REDIS_DATASOURCE_HOST` | Địa chỉ Redis | `0.0.0.0` |
238
+ | `APP_ENV_REDIS_DATASOURCE_PORT` | Cổng Redis | `6379` |
239
+ | `APP_ENV_LOGGER_FOLDER_PATH` | Đường dẫn lưu file log | `./app_data` |
240
+ | `DEBUG` | Kích hoạt log debug | `false` |
292
241
 
293
242
  ---
294
243
 
295
- ## 16. Ví dụ end-to-end: Order Service
244
+ ## 12. Ví dụ end-to-end: Order Service
296
245
 
297
246
  ```typescript
298
247
  // --- 1. Model (order.schema.ts) ---
299
248
  export const orders = pgTable('orders', {
300
249
  ...generateIdColumnDefs({ id: { dataType: 'string' } }),
301
250
  item: text('item').notNull(),
302
- ...generateTzColumnDefs()
251
+ ...generateTzColumnDefs(),
303
252
  });
304
253
 
305
254
  // --- 2. Repository (order.repository.ts) ---
306
255
  export class OrderRepository extends DefaultCrudRepository<typeof orders> {
307
- constructor() { super(orders); }
256
+ constructor() {
257
+ super(orders);
258
+ }
308
259
  }
309
260
 
310
261
  // --- 3. Service (order.service.ts) ---
@@ -320,21 +271,28 @@ export class OrderService extends BaseService {
320
271
  export class OrderController extends BaseController {
321
272
  async binding() {
322
273
  this.bindRoute({
323
- path: '/', method: 'post',
324
- responses: { 200: { description: 'Success' } }
274
+ path: '/',
275
+ method: 'post',
276
+ responses: { 200: { description: 'Success' } },
325
277
  }).to({
326
- handler: async (c) => {
278
+ handler: async c => {
327
279
  const service = this.get<OrderService>('services.OrderService');
328
280
  return c.json(await service.create('Product A'));
329
- }
281
+ },
330
282
  });
331
283
  }
332
284
  }
333
285
 
334
286
  // --- 5. Application (main.ts) ---
335
287
  class OrderApp extends bootMixin(BaseApplication) {
336
- getAppInfo() { return { name: 'OrderAPI', version: '1.0' }; }
288
+ getAppInfo() {
289
+ return { name: 'OrderAPI', version: '1.0' };
290
+ }
337
291
  }
338
292
 
339
293
  bootStrapApplication(OrderApp, { port: 8080 });
340
294
  ```
295
+
296
+ ---
297
+
298
+ © 2024 Gennex Technology. Toàn quyền bảo lưu.
@@ -1,7 +1,7 @@
1
1
  import type { OpenAPIHono } from '@hono/zod-openapi';
2
- import type { Logger } from '../../helpers';
2
+ import { Application, Binding } from '@loopback/core';
3
3
  import type { ValueOrPromise } from '../../common';
4
- import type { ClassType } from '../../common/types';
4
+ import type { Logger } from '../../helpers';
5
5
  export interface IApplicationConfigs {
6
6
  host?: string;
7
7
  port: number;
@@ -24,10 +24,9 @@ export interface IApplicationInfo {
24
24
  export interface IMiddlewareConfigs {
25
25
  [key: string]: any;
26
26
  }
27
- export declare abstract class BaseApplication {
27
+ export declare abstract class BaseApplication extends Application {
28
28
  protected logger: Logger;
29
- protected server: OpenAPIHono;
30
- protected bindings: Map<string, any>;
29
+ protected honoApp: OpenAPIHono;
31
30
  protected configs: IApplicationConfigs;
32
31
  constructor(configs: IApplicationConfigs);
33
32
  abstract getAppInfo(): ValueOrPromise<IApplicationInfo>;
@@ -35,22 +34,7 @@ export declare abstract class BaseApplication {
35
34
  preConfigure(): ValueOrPromise<void>;
36
35
  setupMiddlewares(): Promise<void>;
37
36
  postConfigure(): ValueOrPromise<void>;
38
- controller(_ControllerClass: new (...args: any[]) => any): void;
39
- repository(_RepositoryClass: new (...args: any[]) => any): void;
40
- dataSource(_DataSourceClass: new (...args: any[]) => any): void;
41
- service(_ServiceClass: new (...args: any[]) => any): void;
42
- component(_ComponentClass: new (...args: any[]) => any): void;
43
- bind<T>(opts: {
44
- key: string;
45
- }): {
46
- toValue: (v: T) => void;
47
- toClass: (c: ClassType<T>) => void;
48
- };
49
- get<T>(opts: {
50
- key: string;
51
- isOptional?: boolean;
52
- }): T;
53
- getServer(): OpenAPIHono;
37
+ getHono(): OpenAPIHono;
54
38
  start(): Promise<void>;
55
39
  stop(): Promise<void>;
56
40
  static(_opts: {
@@ -58,5 +42,12 @@ export declare abstract class BaseApplication {
58
42
  mountPath?: string;
59
43
  }): void;
60
44
  protected applyMiddlewares(_configs: IMiddlewareConfigs): Promise<void>;
45
+ bindCustom<T>(opts: {
46
+ key: string;
47
+ }): Binding<T>;
48
+ getCustom<T>(opts: {
49
+ key: string;
50
+ isOptional?: boolean;
51
+ }): ValueOrPromise<T | undefined>;
61
52
  }
62
53
  //# sourceMappingURL=base.application.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base.application.d.ts","sourceRoot":"","sources":["../../../src/base/applications/base.application.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5C,KAAK,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,8BAAsB,eAAe;IACnC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC;IAC9B,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,SAAS,CAAC,OAAO,EAAE,mBAAmB,CAAC;gBAE3B,OAAO,EAAE,mBAAmB;IAQxC,QAAQ,CAAC,UAAU,IAAI,cAAc,CAAC,gBAAgB,CAAC;IAEvD,eAAe,IAAI,IAAI;IACvB,YAAY,IAAI,cAAc,CAAC,IAAI,CAAC;IAC9B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IACvC,aAAa,IAAI,cAAc,CAAC,IAAI,CAAC;IAErC,UAAU,CAAC,gBAAgB,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,IAAI;IAC/D,UAAU,CAAC,gBAAgB,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,IAAI;IAC/D,UAAU,CAAC,gBAAgB,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,IAAI;IAC/D,OAAO,CAAC,aAAa,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,IAAI;IACzD,SAAS,CAAC,eAAe,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,IAAI;IAE7D,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE;qBAEZ,CAAC;qBAGD,SAAS,CAAC,CAAC,CAAC;;IAM7B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,CAAC;IAOtD,SAAS,IAAI,WAAW;IAIlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;cAE/C,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;CAC9E"}
1
+ {"version":3,"file":"base.application.d.ts","sourceRoot":"","sources":["../../../src/base/applications/base.application.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG5C,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5C,KAAK,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,8BAAsB,eAAgB,SAAQ,WAAW;IACvD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC;IAC/B,SAAS,CAAC,OAAO,EAAE,mBAAmB,CAAC;gBAE3B,OAAO,EAAE,mBAAmB;IAQxC,QAAQ,CAAC,UAAU,IAAI,cAAc,CAAC,gBAAgB,CAAC;IAEvD,eAAe,IAAI,IAAI;IACvB,YAAY,IAAI,cAAc,CAAC,IAAI,CAAC;IAC9B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IACvC,aAAa,IAAI,cAAc,CAAC,IAAI,CAAC;IAErC,OAAO,IAAI,WAAW;IAIP,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAetB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;cAE/C,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IAKhD,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc,CAAC,CAAC,GAAG,SAAS,CAAC;CAMzF"}