@dangao/bun-server 2.0.8 → 2.2.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/README.md +4 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/core/application.d.ts +6 -1
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/server.d.ts +5 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/database/database-context.d.ts +25 -0
- package/dist/database/database-context.d.ts.map +1 -0
- package/dist/database/database-extension.d.ts +8 -9
- package/dist/database/database-extension.d.ts.map +1 -1
- package/dist/database/database-module.d.ts +7 -1
- package/dist/database/database-module.d.ts.map +1 -1
- package/dist/database/db-proxy.d.ts +12 -0
- package/dist/database/db-proxy.d.ts.map +1 -0
- package/dist/database/index.d.ts +6 -1
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/orm/transaction-interceptor.d.ts +0 -16
- package/dist/database/orm/transaction-interceptor.d.ts.map +1 -1
- package/dist/database/orm/transaction-manager.d.ts +10 -61
- package/dist/database/orm/transaction-manager.d.ts.map +1 -1
- package/dist/database/service.d.ts.map +1 -1
- package/dist/database/sql-manager.d.ts +14 -0
- package/dist/database/sql-manager.d.ts.map +1 -0
- package/dist/database/sqlite-adapter.d.ts +32 -0
- package/dist/database/sqlite-adapter.d.ts.map +1 -0
- package/dist/database/strategy-decorator.d.ts +8 -0
- package/dist/database/strategy-decorator.d.ts.map +1 -0
- package/dist/database/types.d.ts +122 -1
- package/dist/database/types.d.ts.map +1 -1
- package/dist/di/container.d.ts +16 -0
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/lifecycle.d.ts +48 -0
- package/dist/di/lifecycle.d.ts.map +1 -1
- package/dist/di/module-registry.d.ts +10 -6
- package/dist/di/module-registry.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3267 -2620
- package/dist/microservice/service-registry/service-registry-module.d.ts +16 -0
- package/dist/microservice/service-registry/service-registry-module.d.ts.map +1 -1
- package/dist/router/index.d.ts +1 -0
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/registry.d.ts +1 -1
- package/dist/router/registry.d.ts.map +1 -1
- package/dist/router/route.d.ts +2 -1
- package/dist/router/route.d.ts.map +1 -1
- package/dist/router/router.d.ts +1 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/timeout-decorator.d.ts +6 -0
- package/dist/router/timeout-decorator.d.ts.map +1 -0
- package/docs/database.md +48 -15
- package/docs/idle-timeout.md +42 -0
- package/docs/lifecycle.md +80 -4
- package/docs/microservice-nacos.md +1 -0
- package/docs/microservice-service-registry.md +7 -0
- package/docs/zh/database.md +48 -15
- package/docs/zh/idle-timeout.md +41 -0
- package/docs/zh/lifecycle.md +49 -5
- package/docs/zh/microservice-nacos.md +1 -0
- package/docs/zh/microservice-service-registry.md +6 -0
- package/package.json +1 -1
- package/src/controller/controller.ts +11 -1
- package/src/core/application.ts +98 -26
- package/src/core/server.ts +10 -0
- package/src/database/database-context.ts +43 -0
- package/src/database/database-extension.ts +12 -45
- package/src/database/database-module.ts +254 -11
- package/src/database/db-proxy.ts +75 -0
- package/src/database/index.ts +29 -0
- package/src/database/orm/transaction-interceptor.ts +12 -149
- package/src/database/orm/transaction-manager.ts +143 -210
- package/src/database/service.ts +28 -2
- package/src/database/sql-manager.ts +62 -0
- package/src/database/sqlite-adapter.ts +121 -0
- package/src/database/strategy-decorator.ts +42 -0
- package/src/database/types.ts +133 -1
- package/src/di/container.ts +55 -1
- package/src/di/lifecycle.ts +114 -0
- package/src/di/module-registry.ts +78 -14
- package/src/index.ts +31 -1
- package/src/microservice/service-registry/service-registry-module.ts +25 -1
- package/src/router/index.ts +1 -0
- package/src/router/registry.ts +10 -1
- package/src/router/route.ts +31 -3
- package/src/router/router.ts +10 -1
- package/src/router/timeout-decorator.ts +35 -0
- package/tests/core/application.test.ts +10 -0
- package/tests/database/database-module.test.ts +91 -430
- package/tests/database/db-proxy.test.ts +93 -0
- package/tests/database/sql-manager.test.ts +43 -0
- package/tests/database/sqlite-adapter.test.ts +45 -0
- package/tests/database/strategy-decorator.test.ts +29 -0
- package/tests/database/transaction.test.ts +84 -222
- package/tests/di/lifecycle.test.ts +139 -1
- package/tests/di/scoped-lifecycle.test.ts +61 -0
- package/tests/microservice/service-registry.test.ts +15 -0
- package/tests/router/timeout-decorator.test.ts +48 -0
package/src/database/types.ts
CHANGED
|
@@ -78,6 +78,59 @@ export type DatabaseConfig =
|
|
|
78
78
|
| { type: 'postgres'; config: PostgresConfig }
|
|
79
79
|
| { type: 'mysql'; config: MysqlConfig };
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Bun.SQL 连接池配置
|
|
83
|
+
*/
|
|
84
|
+
export interface BunSQLPoolOptions {
|
|
85
|
+
/**
|
|
86
|
+
* 最大物理连接数
|
|
87
|
+
* @default 10
|
|
88
|
+
*/
|
|
89
|
+
max?: number;
|
|
90
|
+
/**
|
|
91
|
+
* 空闲连接超时(秒)
|
|
92
|
+
* @default 30
|
|
93
|
+
*/
|
|
94
|
+
idleTimeout?: number;
|
|
95
|
+
/**
|
|
96
|
+
* 连接最大生存时间(秒)
|
|
97
|
+
* @default 0
|
|
98
|
+
*/
|
|
99
|
+
maxLifetime?: number;
|
|
100
|
+
/**
|
|
101
|
+
* 获取连接超时(毫秒)
|
|
102
|
+
* @default 30000
|
|
103
|
+
*/
|
|
104
|
+
connectionTimeout?: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Bun.SQL 配置(Postgres/MySQL)
|
|
109
|
+
*/
|
|
110
|
+
export interface BunSQLConfig {
|
|
111
|
+
type: 'postgres' | 'mysql';
|
|
112
|
+
url: string;
|
|
113
|
+
pool?: BunSQLPoolOptions;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* SQLite V2 配置
|
|
118
|
+
*/
|
|
119
|
+
export interface SqliteV2Config {
|
|
120
|
+
type: 'sqlite';
|
|
121
|
+
database: string;
|
|
122
|
+
wal?: boolean;
|
|
123
|
+
maxWriteConcurrency?: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 多租户配置
|
|
128
|
+
*/
|
|
129
|
+
export interface TenantConfig {
|
|
130
|
+
id: string;
|
|
131
|
+
config: BunSQLConfig | SqliteV2Config;
|
|
132
|
+
}
|
|
133
|
+
|
|
81
134
|
/**
|
|
82
135
|
* 连接池配置
|
|
83
136
|
*/
|
|
@@ -108,12 +161,59 @@ export interface ConnectionPoolOptions {
|
|
|
108
161
|
* DatabaseModule 配置选项
|
|
109
162
|
*/
|
|
110
163
|
export interface DatabaseModuleOptions {
|
|
164
|
+
/**
|
|
165
|
+
* 全局默认连接策略
|
|
166
|
+
* - pool: 每次查询走共享池(默认)
|
|
167
|
+
* - session: 首次查询惰性 reserve,整个请求复用同一连接
|
|
168
|
+
* @default "pool"
|
|
169
|
+
*/
|
|
170
|
+
defaultStrategy?: 'pool' | 'session';
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 多租户配置
|
|
174
|
+
*/
|
|
175
|
+
tenants?: TenantConfig[];
|
|
176
|
+
/**
|
|
177
|
+
* 默认租户 ID
|
|
178
|
+
* @default "default"
|
|
179
|
+
*/
|
|
180
|
+
defaultTenant?: string;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 单租户:数据库类型(V2)
|
|
184
|
+
*/
|
|
185
|
+
type?: DatabaseType;
|
|
186
|
+
/**
|
|
187
|
+
* 单租户:Postgres/MySQL URL(V2)
|
|
188
|
+
*/
|
|
189
|
+
url?: string;
|
|
190
|
+
/**
|
|
191
|
+
* 单租户:SQLite 文件路径(V2)
|
|
192
|
+
*/
|
|
193
|
+
databasePath?: string;
|
|
194
|
+
/**
|
|
195
|
+
* 单租户:SQLite WAL 模式
|
|
196
|
+
* @default true
|
|
197
|
+
*/
|
|
198
|
+
wal?: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* 单租户:SQLite 最大写并发
|
|
201
|
+
* @default 1
|
|
202
|
+
*/
|
|
203
|
+
maxWriteConcurrency?: number;
|
|
204
|
+
/**
|
|
205
|
+
* Bun.SQL 连接池参数(V2)
|
|
206
|
+
*/
|
|
207
|
+
bunSqlPool?: BunSQLPoolOptions;
|
|
208
|
+
|
|
111
209
|
/**
|
|
112
210
|
* 数据库配置
|
|
211
|
+
* @deprecated 使用 V2 字段(type/url/databasePath)或 tenants
|
|
113
212
|
*/
|
|
114
|
-
database
|
|
213
|
+
database?: DatabaseConfig;
|
|
115
214
|
/**
|
|
116
215
|
* 连接池配置
|
|
216
|
+
* @deprecated 旧连接池配置,仅用于兼容旧 DatabaseService
|
|
117
217
|
*/
|
|
118
218
|
pool?: ConnectionPoolOptions;
|
|
119
219
|
/**
|
|
@@ -135,6 +235,23 @@ export interface DatabaseModuleOptions {
|
|
|
135
235
|
*/
|
|
136
236
|
drizzle?: unknown;
|
|
137
237
|
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @deprecated 旧字段兼容(用于构造 URL)
|
|
241
|
+
*/
|
|
242
|
+
host?: string;
|
|
243
|
+
/**
|
|
244
|
+
* @deprecated 旧字段兼容(用于构造 URL)
|
|
245
|
+
*/
|
|
246
|
+
port?: number;
|
|
247
|
+
/**
|
|
248
|
+
* @deprecated 旧字段兼容(用于构造 URL)
|
|
249
|
+
*/
|
|
250
|
+
username?: string;
|
|
251
|
+
/**
|
|
252
|
+
* @deprecated 旧字段兼容(用于构造 URL)
|
|
253
|
+
*/
|
|
254
|
+
password?: string;
|
|
138
255
|
}
|
|
139
256
|
|
|
140
257
|
/**
|
|
@@ -169,3 +286,18 @@ export const DATABASE_SERVICE_TOKEN = Symbol('@dangao/bun-server:database:servic
|
|
|
169
286
|
* DatabaseModule Options Token
|
|
170
287
|
*/
|
|
171
288
|
export const DATABASE_OPTIONS_TOKEN = Symbol('@dangao/bun-server:database:options');
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* BunSQLManager Token
|
|
292
|
+
*/
|
|
293
|
+
export const BUN_SQL_MANAGER_TOKEN = Symbol('@dangao/bun-server:database:bun-sql-manager');
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* SQLite manager Token
|
|
297
|
+
*/
|
|
298
|
+
export const SQLITE_MANAGER_TOKEN = Symbol('@dangao/bun-server:database:sqlite-manager');
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* db proxy Token
|
|
302
|
+
*/
|
|
303
|
+
export const DB_TOKEN = Symbol('@dangao/bun-server:database:db');
|
package/src/di/container.ts
CHANGED
|
@@ -14,6 +14,13 @@ import {
|
|
|
14
14
|
import { LoggerManager } from "@dangao/logsmith";
|
|
15
15
|
import type { Constructor } from "@/core/types";
|
|
16
16
|
import { contextStore } from "../core/context-service";
|
|
17
|
+
import {
|
|
18
|
+
callComponentBeforeCreate,
|
|
19
|
+
callOnAfterCreate,
|
|
20
|
+
callOnBeforeDestroy,
|
|
21
|
+
callOnModuleDestroy,
|
|
22
|
+
callOnAfterDestroy,
|
|
23
|
+
} from "./lifecycle";
|
|
17
24
|
|
|
18
25
|
/**
|
|
19
26
|
* 依赖注入容器
|
|
@@ -365,6 +372,7 @@ export class Container {
|
|
|
365
372
|
* @returns 实例
|
|
366
373
|
*/
|
|
367
374
|
private instantiate<T>(constructor: Constructor<T>): T {
|
|
375
|
+
callComponentBeforeCreate(constructor);
|
|
368
376
|
const plan = this.getDependencyPlan(constructor);
|
|
369
377
|
|
|
370
378
|
let instance: T;
|
|
@@ -379,7 +387,9 @@ export class Container {
|
|
|
379
387
|
}
|
|
380
388
|
|
|
381
389
|
// 应用后处理器
|
|
382
|
-
|
|
390
|
+
const processed = this.applyPostProcessors(instance, constructor);
|
|
391
|
+
callOnAfterCreate(processed);
|
|
392
|
+
return processed;
|
|
383
393
|
}
|
|
384
394
|
|
|
385
395
|
/**
|
|
@@ -409,6 +419,50 @@ export class Container {
|
|
|
409
419
|
// scopedInstances 使用 WeakMap,当 Context 对象被 GC 时会自动清理
|
|
410
420
|
}
|
|
411
421
|
|
|
422
|
+
/**
|
|
423
|
+
* 获取指定请求上下文下的 scoped 实例
|
|
424
|
+
* @param context - 请求上下文对象
|
|
425
|
+
* @returns 去重后的 scoped 实例列表
|
|
426
|
+
*/
|
|
427
|
+
public getScopedInstances(context: object): unknown[] {
|
|
428
|
+
const scopedMap = this.scopedInstances.get(context);
|
|
429
|
+
if (!scopedMap || scopedMap.size === 0) {
|
|
430
|
+
return [];
|
|
431
|
+
}
|
|
432
|
+
const seen = new Set<unknown>();
|
|
433
|
+
const instances: unknown[] = [];
|
|
434
|
+
for (const instance of scopedMap.values()) {
|
|
435
|
+
if (!seen.has(instance)) {
|
|
436
|
+
seen.add(instance);
|
|
437
|
+
instances.push(instance);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return instances;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* 清理指定请求上下文的 scoped 实例缓存
|
|
445
|
+
* @param context - 请求上下文对象
|
|
446
|
+
*/
|
|
447
|
+
public clearScopedInstances(context: object): void {
|
|
448
|
+
this.scopedInstances.delete(context);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* 触发指定请求上下文下 scoped 实例的销毁钩子并清理缓存
|
|
453
|
+
* @param context - 请求上下文对象
|
|
454
|
+
*/
|
|
455
|
+
public async disposeScopedInstances(context: object): Promise<void> {
|
|
456
|
+
const instances = this.getScopedInstances(context);
|
|
457
|
+
if (instances.length === 0) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
await callOnBeforeDestroy(instances);
|
|
461
|
+
await callOnModuleDestroy(instances);
|
|
462
|
+
await callOnAfterDestroy(instances);
|
|
463
|
+
this.clearScopedInstances(context);
|
|
464
|
+
}
|
|
465
|
+
|
|
412
466
|
/**
|
|
413
467
|
* 检查是否已注册
|
|
414
468
|
* @param token - 提供者标识符
|
package/src/di/lifecycle.ts
CHANGED
|
@@ -30,6 +30,38 @@ export interface OnApplicationShutdown {
|
|
|
30
30
|
onApplicationShutdown(signal?: string): Promise<void> | void;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* 组件创建前钩子(静态类方法)
|
|
35
|
+
* 在实例化前调用,适用于 Controller / Injectable 类
|
|
36
|
+
*/
|
|
37
|
+
export type ComponentClassBeforeCreate = {
|
|
38
|
+
onBeforeCreate(): void;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 组件创建后钩子(实例)
|
|
43
|
+
* 在实例化并完成后处理后调用
|
|
44
|
+
*/
|
|
45
|
+
export interface OnAfterCreate {
|
|
46
|
+
onAfterCreate(): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 组件销毁前钩子(实例)
|
|
51
|
+
* 在 onModuleDestroy 之前调用(反向顺序)
|
|
52
|
+
*/
|
|
53
|
+
export interface OnBeforeDestroy {
|
|
54
|
+
onBeforeDestroy(): Promise<void> | void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 组件销毁后钩子(实例)
|
|
59
|
+
* 在 onModuleDestroy 之后调用(反向顺序)
|
|
60
|
+
*/
|
|
61
|
+
export interface OnAfterDestroy {
|
|
62
|
+
onAfterDestroy(): Promise<void> | void;
|
|
63
|
+
}
|
|
64
|
+
|
|
33
65
|
export function hasOnModuleInit(instance: unknown): instance is OnModuleInit {
|
|
34
66
|
return (
|
|
35
67
|
instance !== null &&
|
|
@@ -70,6 +102,64 @@ export function hasOnApplicationShutdown(instance: unknown): instance is OnAppli
|
|
|
70
102
|
);
|
|
71
103
|
}
|
|
72
104
|
|
|
105
|
+
export function hasComponentBeforeCreate(target: unknown): target is ComponentClassBeforeCreate {
|
|
106
|
+
return (
|
|
107
|
+
target !== null &&
|
|
108
|
+
target !== undefined &&
|
|
109
|
+
typeof target === 'function' &&
|
|
110
|
+
'onBeforeCreate' in target &&
|
|
111
|
+
typeof (target as ComponentClassBeforeCreate).onBeforeCreate === 'function'
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function hasOnAfterCreate(instance: unknown): instance is OnAfterCreate {
|
|
116
|
+
return (
|
|
117
|
+
instance !== null &&
|
|
118
|
+
instance !== undefined &&
|
|
119
|
+
typeof instance === 'object' &&
|
|
120
|
+
'onAfterCreate' in instance &&
|
|
121
|
+
typeof (instance as OnAfterCreate).onAfterCreate === 'function'
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function hasOnBeforeDestroy(instance: unknown): instance is OnBeforeDestroy {
|
|
126
|
+
return (
|
|
127
|
+
instance !== null &&
|
|
128
|
+
instance !== undefined &&
|
|
129
|
+
typeof instance === 'object' &&
|
|
130
|
+
'onBeforeDestroy' in instance &&
|
|
131
|
+
typeof (instance as OnBeforeDestroy).onBeforeDestroy === 'function'
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function hasOnAfterDestroy(instance: unknown): instance is OnAfterDestroy {
|
|
136
|
+
return (
|
|
137
|
+
instance !== null &&
|
|
138
|
+
instance !== undefined &&
|
|
139
|
+
typeof instance === 'object' &&
|
|
140
|
+
'onAfterDestroy' in instance &&
|
|
141
|
+
typeof (instance as OnAfterDestroy).onAfterDestroy === 'function'
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 调用组件类静态 onBeforeCreate
|
|
147
|
+
*/
|
|
148
|
+
export function callComponentBeforeCreate(target: unknown): void {
|
|
149
|
+
if (hasComponentBeforeCreate(target)) {
|
|
150
|
+
target.onBeforeCreate();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 调用组件实例 onAfterCreate
|
|
156
|
+
*/
|
|
157
|
+
export function callOnAfterCreate(instance: unknown): void {
|
|
158
|
+
if (hasOnAfterCreate(instance)) {
|
|
159
|
+
instance.onAfterCreate();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
73
163
|
/**
|
|
74
164
|
* 按顺序调用 onModuleInit
|
|
75
165
|
*/
|
|
@@ -115,3 +205,27 @@ export async function callOnApplicationShutdown(instances: unknown[], signal?: s
|
|
|
115
205
|
}
|
|
116
206
|
}
|
|
117
207
|
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 按反向顺序调用 onBeforeDestroy
|
|
211
|
+
*/
|
|
212
|
+
export async function callOnBeforeDestroy(instances: unknown[]): Promise<void> {
|
|
213
|
+
for (let i = instances.length - 1; i >= 0; i--) {
|
|
214
|
+
const instance = instances[i];
|
|
215
|
+
if (hasOnBeforeDestroy(instance)) {
|
|
216
|
+
await instance.onBeforeDestroy();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 按反向顺序调用 onAfterDestroy
|
|
223
|
+
*/
|
|
224
|
+
export async function callOnAfterDestroy(instances: unknown[]): Promise<void> {
|
|
225
|
+
for (let i = instances.length - 1; i >= 0; i--) {
|
|
226
|
+
const instance = instances[i];
|
|
227
|
+
if (hasOnAfterDestroy(instance)) {
|
|
228
|
+
await instance.onAfterDestroy();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
callOnModuleDestroy,
|
|
12
12
|
callOnApplicationBootstrap,
|
|
13
13
|
callOnApplicationShutdown,
|
|
14
|
+
callOnBeforeDestroy,
|
|
15
|
+
callOnAfterDestroy,
|
|
14
16
|
} from './lifecycle';
|
|
15
17
|
|
|
16
18
|
interface ModuleRef {
|
|
@@ -225,63 +227,125 @@ export class ModuleRegistry {
|
|
|
225
227
|
}
|
|
226
228
|
|
|
227
229
|
/**
|
|
228
|
-
*
|
|
230
|
+
* 解析所有模块中的组件实例(providers + controllers),用于生命周期钩子调用
|
|
229
231
|
*/
|
|
230
|
-
public
|
|
232
|
+
public resolveAllComponentInstances(): unknown[] {
|
|
231
233
|
const instances: unknown[] = [];
|
|
234
|
+
const seen = new Set<unknown>();
|
|
232
235
|
for (const [, ref] of this.moduleRefs) {
|
|
233
236
|
for (const provider of ref.metadata.providers) {
|
|
234
237
|
try {
|
|
235
238
|
if (typeof provider === 'function') {
|
|
236
|
-
|
|
239
|
+
const instance = ref.container.resolve(provider);
|
|
240
|
+
if (!seen.has(instance)) {
|
|
241
|
+
seen.add(instance);
|
|
242
|
+
instances.push(instance);
|
|
243
|
+
}
|
|
237
244
|
} else if ('useClass' in provider) {
|
|
238
245
|
const token = provider.provide ?? provider.useClass;
|
|
239
|
-
|
|
246
|
+
const instance = ref.container.resolve(token as Constructor<unknown>);
|
|
247
|
+
if (!seen.has(instance)) {
|
|
248
|
+
seen.add(instance);
|
|
249
|
+
instances.push(instance);
|
|
250
|
+
}
|
|
240
251
|
} else if ('useValue' in provider) {
|
|
241
|
-
|
|
252
|
+
if (!seen.has(provider.useValue)) {
|
|
253
|
+
seen.add(provider.useValue);
|
|
254
|
+
instances.push(provider.useValue);
|
|
255
|
+
}
|
|
242
256
|
} else if ('useFactory' in provider) {
|
|
243
|
-
|
|
257
|
+
const instance = ref.container.resolve(provider.provide as Constructor<unknown>);
|
|
258
|
+
if (!seen.has(instance)) {
|
|
259
|
+
seen.add(instance);
|
|
260
|
+
instances.push(instance);
|
|
261
|
+
}
|
|
244
262
|
}
|
|
245
263
|
} catch (_error) {
|
|
246
264
|
// skip providers that can't be resolved (e.g. pending async providers)
|
|
247
265
|
}
|
|
248
266
|
}
|
|
267
|
+
for (const controller of ref.metadata.controllers) {
|
|
268
|
+
try {
|
|
269
|
+
const instance = ref.container.resolve(controller);
|
|
270
|
+
if (!seen.has(instance)) {
|
|
271
|
+
seen.add(instance);
|
|
272
|
+
instances.push(instance);
|
|
273
|
+
}
|
|
274
|
+
} catch (_error) {
|
|
275
|
+
// skip controllers that can't be resolved
|
|
276
|
+
}
|
|
277
|
+
}
|
|
249
278
|
}
|
|
250
279
|
return instances;
|
|
251
280
|
}
|
|
252
281
|
|
|
253
282
|
/**
|
|
254
|
-
*
|
|
283
|
+
* 调用所有组件(providers + controllers)的 onModuleInit 钩子
|
|
255
284
|
*/
|
|
256
285
|
public async callModuleInitHooks(): Promise<void> {
|
|
257
|
-
const instances = this.
|
|
286
|
+
const instances = this.resolveAllComponentInstances();
|
|
258
287
|
await callOnModuleInit(instances);
|
|
259
288
|
}
|
|
260
289
|
|
|
261
290
|
/**
|
|
262
|
-
*
|
|
291
|
+
* 调用所有组件(providers + controllers)的 onApplicationBootstrap 钩子
|
|
263
292
|
*/
|
|
264
293
|
public async callBootstrapHooks(): Promise<void> {
|
|
265
|
-
const instances = this.
|
|
294
|
+
const instances = this.resolveAllComponentInstances();
|
|
266
295
|
await callOnApplicationBootstrap(instances);
|
|
267
296
|
}
|
|
268
297
|
|
|
269
298
|
/**
|
|
270
|
-
*
|
|
299
|
+
* 调用所有组件(providers + controllers)的 onModuleDestroy 钩子
|
|
271
300
|
*/
|
|
272
301
|
public async callModuleDestroyHooks(): Promise<void> {
|
|
273
|
-
const instances = this.
|
|
302
|
+
const instances = this.resolveAllComponentInstances();
|
|
303
|
+
await callOnBeforeDestroy(instances);
|
|
274
304
|
await callOnModuleDestroy(instances);
|
|
305
|
+
await callOnAfterDestroy(instances);
|
|
275
306
|
}
|
|
276
307
|
|
|
277
308
|
/**
|
|
278
|
-
*
|
|
309
|
+
* 调用所有组件(providers + controllers)的 onApplicationShutdown 钩子
|
|
279
310
|
*/
|
|
280
311
|
public async callShutdownHooks(signal?: string): Promise<void> {
|
|
281
|
-
const instances = this.
|
|
312
|
+
const instances = this.resolveAllComponentInstances();
|
|
282
313
|
await callOnApplicationShutdown(instances, signal);
|
|
283
314
|
}
|
|
284
315
|
|
|
316
|
+
/**
|
|
317
|
+
* 调用当前请求上下文下 scoped 组件的销毁钩子并清理缓存
|
|
318
|
+
*/
|
|
319
|
+
public async disposeScopedInstances(context: object): Promise<void> {
|
|
320
|
+
const containers: Container[] = [];
|
|
321
|
+
if (this.rootContainer) {
|
|
322
|
+
containers.push(this.rootContainer);
|
|
323
|
+
}
|
|
324
|
+
containers.push(...this.getAllModuleContainers());
|
|
325
|
+
|
|
326
|
+
const instances: unknown[] = [];
|
|
327
|
+
const seen = new Set<unknown>();
|
|
328
|
+
for (const container of containers) {
|
|
329
|
+
const scopedInstances = container.getScopedInstances(context);
|
|
330
|
+
for (const instance of scopedInstances) {
|
|
331
|
+
if (!seen.has(instance)) {
|
|
332
|
+
seen.add(instance);
|
|
333
|
+
instances.push(instance);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (instances.length > 0) {
|
|
339
|
+
await callOnBeforeDestroy(instances);
|
|
340
|
+
await callOnModuleDestroy(instances);
|
|
341
|
+
await callOnAfterDestroy(instances);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
for (const container of containers) {
|
|
345
|
+
container.clearScopedInstances(context);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
285
349
|
private registerExport(parentContainer: Container, moduleRef: ModuleRef, token: ProviderToken): void {
|
|
286
350
|
if (!moduleRef.container.isRegistered(token)) {
|
|
287
351
|
throw new Error(
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { BunServer, type ServerOptions } from './core/server';
|
|
|
4
4
|
export { ClusterManager, type ClusterOptions, type ClusterMode } from './core/cluster';
|
|
5
5
|
export { Context } from './core/context';
|
|
6
6
|
export { ContextService, CONTEXT_SERVICE_TOKEN, contextStore } from './core/context-service';
|
|
7
|
-
export { Route, Router, RouteRegistry } from './router';
|
|
7
|
+
export { Route, Router, RouteRegistry, IdleTimeout } from './router';
|
|
8
8
|
export { GET, POST, PUT, DELETE, PATCH } from './router/decorators';
|
|
9
9
|
export type { HttpMethod, RouteHandler, RouteMatch } from './router/types';
|
|
10
10
|
export { BodyParser, RequestWrapper, ResponseBuilder } from './request';
|
|
@@ -42,6 +42,10 @@ export type {
|
|
|
42
42
|
OnModuleDestroy,
|
|
43
43
|
OnApplicationBootstrap,
|
|
44
44
|
OnApplicationShutdown,
|
|
45
|
+
ComponentClassBeforeCreate,
|
|
46
|
+
OnAfterCreate,
|
|
47
|
+
OnBeforeDestroy,
|
|
48
|
+
OnAfterDestroy,
|
|
45
49
|
} from './di/lifecycle';
|
|
46
50
|
export {
|
|
47
51
|
InterceptorRegistry,
|
|
@@ -307,16 +311,41 @@ export {
|
|
|
307
311
|
ConnectionPool,
|
|
308
312
|
DatabaseHealthIndicator,
|
|
309
313
|
DatabaseExtension,
|
|
314
|
+
BunSQLManager,
|
|
315
|
+
SqliteAdapter,
|
|
316
|
+
SqliteManager,
|
|
317
|
+
Semaphore,
|
|
318
|
+
db,
|
|
319
|
+
initDbProxy,
|
|
320
|
+
DbStrategy,
|
|
321
|
+
DbSession,
|
|
322
|
+
DB_STRATEGY_KEY,
|
|
323
|
+
getDbStrategy,
|
|
324
|
+
databaseSessionStore,
|
|
325
|
+
getCurrentSession,
|
|
326
|
+
runWithSession,
|
|
310
327
|
DATABASE_SERVICE_TOKEN,
|
|
311
328
|
DATABASE_OPTIONS_TOKEN,
|
|
329
|
+
BUN_SQL_MANAGER_TOKEN,
|
|
330
|
+
SQLITE_MANAGER_TOKEN,
|
|
331
|
+
DB_TOKEN,
|
|
312
332
|
type DatabaseModuleOptions,
|
|
313
333
|
type DatabaseConfig,
|
|
314
334
|
type DatabaseType,
|
|
315
335
|
type ConnectionInfo,
|
|
316
336
|
type ConnectionPoolOptions,
|
|
337
|
+
type BunSQLConfig,
|
|
338
|
+
type BunSQLPoolOptions,
|
|
317
339
|
type SqliteConfig,
|
|
340
|
+
type SqliteV2Config,
|
|
318
341
|
type PostgresConfig,
|
|
319
342
|
type MysqlConfig,
|
|
343
|
+
type TenantConfig,
|
|
344
|
+
type DbStrategyType,
|
|
345
|
+
type DbProxy,
|
|
346
|
+
type DatabaseSession,
|
|
347
|
+
type TransactionState as DatabaseTransactionState,
|
|
348
|
+
type ReservedSqlSession,
|
|
320
349
|
// ORM exports
|
|
321
350
|
Entity,
|
|
322
351
|
Column,
|
|
@@ -472,6 +501,7 @@ export {
|
|
|
472
501
|
} from './microservice';
|
|
473
502
|
export {
|
|
474
503
|
ServiceRegistryModule,
|
|
504
|
+
ServiceRegistryDecorator,
|
|
475
505
|
NacosServiceRegistry,
|
|
476
506
|
SERVICE_REGISTRY_TOKEN,
|
|
477
507
|
type ServiceRegistryModuleOptions,
|
|
@@ -2,7 +2,11 @@ import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../../di/modul
|
|
|
2
2
|
import { NacosClient } from '@dangao/nacos-client';
|
|
3
3
|
import type { NacosClientOptions } from '@dangao/nacos-client';
|
|
4
4
|
import { NacosServiceRegistry } from './nacos-service-registry';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
SERVICE_REGISTRY_TOKEN,
|
|
7
|
+
type ServiceRegistry,
|
|
8
|
+
type ServiceInstance,
|
|
9
|
+
} from './types';
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* 服务注册中心 Provider 类型
|
|
@@ -45,6 +49,21 @@ export interface ServiceRegistryModuleOptions {
|
|
|
45
49
|
*/
|
|
46
50
|
nacos?: NacosServiceRegistryOptions;
|
|
47
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 是否自动在 Application.listen 时注册带 @ServiceRegistry 的服务
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
autoRegister?: boolean;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 通过模块配置自动注册服务(无需 @ServiceRegistry 装饰器)
|
|
60
|
+
* 当 autoRegister=true 时在 Application.listen 阶段自动注册
|
|
61
|
+
*/
|
|
62
|
+
autoRegisterService?: Omit<ServiceInstance, 'ip' | 'port'> & {
|
|
63
|
+
ip?: string;
|
|
64
|
+
port?: number;
|
|
65
|
+
};
|
|
66
|
+
|
|
48
67
|
// 未来可以添加其他 provider 的配置
|
|
49
68
|
// consul?: ConsulServiceRegistryOptions;
|
|
50
69
|
// eureka?: EurekaServiceRegistryOptions;
|
|
@@ -57,11 +76,16 @@ export interface ServiceRegistryModuleOptions {
|
|
|
57
76
|
providers: [],
|
|
58
77
|
})
|
|
59
78
|
export class ServiceRegistryModule {
|
|
79
|
+
public static autoRegister = true;
|
|
80
|
+
public static autoRegisterService: ServiceRegistryModuleOptions['autoRegisterService'];
|
|
81
|
+
|
|
60
82
|
/**
|
|
61
83
|
* 创建服务注册中心模块
|
|
62
84
|
* @param options - 模块配置
|
|
63
85
|
*/
|
|
64
86
|
public static forRoot(options: ServiceRegistryModuleOptions): typeof ServiceRegistryModule {
|
|
87
|
+
ServiceRegistryModule.autoRegister = options.autoRegister ?? true;
|
|
88
|
+
ServiceRegistryModule.autoRegisterService = options.autoRegisterService;
|
|
65
89
|
const providers: ModuleProvider[] = [];
|
|
66
90
|
|
|
67
91
|
let serviceRegistry: ServiceRegistry;
|
package/src/router/index.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { Route } from './route';
|
|
|
2
2
|
export { Router } from './router';
|
|
3
3
|
export { RouteRegistry } from './registry';
|
|
4
4
|
export { GET, POST, PUT, DELETE, PATCH } from './decorators';
|
|
5
|
+
export { IdleTimeout, IDLE_TIMEOUT_KEY, getIdleTimeout } from './timeout-decorator';
|
|
5
6
|
export type { HttpMethod, RouteHandler, RouteMatch } from './types';
|
|
6
7
|
|
package/src/router/registry.ts
CHANGED
|
@@ -42,8 +42,17 @@ export class RouteRegistry {
|
|
|
42
42
|
middlewares: Middleware[] = [],
|
|
43
43
|
controllerClass?: Constructor<unknown>,
|
|
44
44
|
methodName?: string,
|
|
45
|
+
timeout?: number,
|
|
45
46
|
): void {
|
|
46
|
-
this.router.register(
|
|
47
|
+
this.router.register(
|
|
48
|
+
method,
|
|
49
|
+
path,
|
|
50
|
+
handler,
|
|
51
|
+
middlewares,
|
|
52
|
+
controllerClass,
|
|
53
|
+
methodName,
|
|
54
|
+
timeout,
|
|
55
|
+
);
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/**
|