@dangao/bun-server 1.8.3 → 1.10.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 +60 -6
- package/dist/core/application.d.ts +12 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/server.d.ts +7 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/events/event-module.d.ts +4 -0
- package/dist/events/event-module.d.ts.map +1 -1
- package/dist/events/types.d.ts +16 -0
- package/dist/events/types.d.ts.map +1 -1
- package/dist/index.js +4969 -4882
- package/docs/custom-decorators.md +1 -7
- package/docs/extensions.md +0 -2
- package/docs/guide.md +0 -1
- package/docs/zh/custom-decorators.md +1 -7
- package/docs/zh/extensions.md +0 -2
- package/docs/zh/guide.md +0 -1
- package/docs/zh/migration.md +0 -5
- package/package.json +4 -4
- package/src/core/application.ts +38 -0
- package/src/core/server.ts +9 -0
- package/src/events/event-module.ts +108 -0
- package/src/events/types.ts +19 -0
- package/tests/auth/auth-decorators.test.ts +0 -1
- package/tests/auth/oauth2-service.test.ts +0 -1
- package/tests/cache/cache-decorators-extended.test.ts +0 -1
- package/tests/cache/cache-decorators.test.ts +0 -1
- package/tests/cache/cache-interceptors.test.ts +0 -1
- package/tests/cache/cache-module.test.ts +0 -1
- package/tests/cache/cache-service-proxy.test.ts +0 -1
- package/tests/config/config-center-integration.test.ts +0 -1
- package/tests/config/config-module-extended.test.ts +0 -1
- package/tests/config/config-module.test.ts +0 -1
- package/tests/controller/controller.test.ts +0 -1
- package/tests/controller/param-binder.test.ts +0 -1
- package/tests/controller/path-combination.test.ts +0 -1
- package/tests/core/application.test.ts +34 -0
- package/tests/database/database-module.test.ts +0 -1
- package/tests/database/orm.test.ts +0 -1
- package/tests/database/postgres-mysql-integration.test.ts +0 -1
- package/tests/database/transaction.test.ts +0 -1
- package/tests/di/container.test.ts +0 -1
- package/tests/error/error-handler.test.ts +0 -1
- package/tests/events/event-decorators.test.ts +0 -1
- package/tests/events/event-listener-scanner.test.ts +0 -1
- package/tests/events/event-module.test.ts +0 -1
- package/tests/extensions/logger-module.test.ts +0 -1
- package/tests/health/health-module.test.ts +0 -1
- package/tests/integration/oauth2-e2e.test.ts +0 -1
- package/tests/integration/session-e2e.test.ts +0 -1
- package/tests/interceptor/base-interceptor.test.ts +0 -1
- package/tests/interceptor/builtin/cache-interceptor.test.ts +0 -1
- package/tests/interceptor/builtin/log-interceptor.test.ts +0 -1
- package/tests/interceptor/builtin/permission-interceptor.test.ts +0 -1
- package/tests/interceptor/interceptor-advanced-integration.test.ts +0 -1
- package/tests/interceptor/interceptor-chain.test.ts +0 -1
- package/tests/interceptor/interceptor-integration.test.ts +0 -1
- package/tests/interceptor/interceptor-metadata.test.ts +0 -1
- package/tests/interceptor/interceptor-registry.test.ts +0 -1
- package/tests/interceptor/perf/interceptor-performance.test.ts +0 -1
- package/tests/metrics/metrics-module.test.ts +0 -1
- package/tests/microservice/config-center.test.ts +0 -1
- package/tests/microservice/service-client-decorators.test.ts +0 -1
- package/tests/microservice/service-registry-decorators.test.ts +0 -1
- package/tests/microservice/service-registry.test.ts +0 -1
- package/tests/middleware/builtin/middleware-builtin-extended.test.ts +0 -1
- package/tests/middleware/builtin/rate-limit.test.ts +0 -1
- package/tests/middleware/middleware-decorators.test.ts +0 -1
- package/tests/middleware/middleware-pipeline.test.ts +0 -1
- package/tests/middleware/middleware.test.ts +0 -1
- package/tests/perf/optimization.test.ts +0 -1
- package/tests/queue/queue-decorators.test.ts +0 -1
- package/tests/queue/queue-module.test.ts +0 -1
- package/tests/queue/queue-service.test.ts +0 -1
- package/tests/router/router-decorators.test.ts +0 -1
- package/tests/router/router-extended.test.ts +0 -1
- package/tests/security/guards/guards-integration.test.ts +0 -1
- package/tests/security/guards/guards.test.ts +0 -1
- package/tests/security/guards/reflector.test.ts +0 -1
- package/tests/security/security-filter.test.ts +0 -1
- package/tests/security/security-module-extended.test.ts +0 -1
- package/tests/security/security-module.test.ts +0 -1
- package/tests/session/session-decorators.test.ts +0 -1
- package/tests/session/session-module.test.ts +0 -1
- package/tests/swagger/decorators.test.ts +0 -1
- package/tests/swagger/swagger-module.test.ts +0 -1
- package/tests/swagger/ui.test.ts +0 -1
- package/tests/validation/class-validator.test.ts +0 -1
- package/tests/validation/controller-validation.test.ts +0 -1
|
@@ -27,11 +27,9 @@ Bun Server Framework provides a powerful interceptor mechanism that allows you t
|
|
|
27
27
|
|
|
28
28
|
### Basic Decorator Pattern
|
|
29
29
|
|
|
30
|
-
A custom decorator is a function that returns a `MethodDecorator`. It uses
|
|
30
|
+
A custom decorator is a function that returns a `MethodDecorator`. It uses the Reflect metadata API to store metadata on the method.
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
|
-
import 'reflect-metadata';
|
|
34
|
-
|
|
35
33
|
// 1. Define a metadata key (use Symbol for uniqueness)
|
|
36
34
|
export const MY_METADATA_KEY = Symbol('@my-app:my-decorator');
|
|
37
35
|
|
|
@@ -260,8 +258,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
260
258
|
### Storing Metadata
|
|
261
259
|
|
|
262
260
|
```typescript
|
|
263
|
-
import 'reflect-metadata';
|
|
264
|
-
|
|
265
261
|
const METADATA_KEY = Symbol('my-metadata');
|
|
266
262
|
|
|
267
263
|
// Store metadata
|
|
@@ -337,7 +333,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
337
333
|
### Example 1: Simple Logging Interceptor
|
|
338
334
|
|
|
339
335
|
```typescript
|
|
340
|
-
import 'reflect-metadata';
|
|
341
336
|
import { BaseInterceptor } from '@dangao/bun-server';
|
|
342
337
|
import type { Container } from '@dangao/bun-server';
|
|
343
338
|
import type { Context } from '@dangao/bun-server';
|
|
@@ -375,7 +370,6 @@ export class LogInterceptor extends BaseInterceptor {
|
|
|
375
370
|
### Example 2: Rate Limiting Interceptor
|
|
376
371
|
|
|
377
372
|
```typescript
|
|
378
|
-
import 'reflect-metadata';
|
|
379
373
|
import { BaseInterceptor, HttpException } from '@dangao/bun-server';
|
|
380
374
|
import type { Container } from '@dangao/bun-server';
|
|
381
375
|
import type { Context } from '@dangao/bun-server';
|
package/docs/extensions.md
CHANGED
|
@@ -499,8 +499,6 @@ You can create custom decorators to extend controller and route functionality.
|
|
|
499
499
|
### Creating Decorators
|
|
500
500
|
|
|
501
501
|
```typescript
|
|
502
|
-
import 'reflect-metadata';
|
|
503
|
-
|
|
504
502
|
// Cache decorator
|
|
505
503
|
export function Cache(ttl: number) {
|
|
506
504
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
package/docs/guide.md
CHANGED
|
@@ -29,12 +29,10 @@ AOP(面向切面编程)。这使您能够添加横切关注点,如缓存
|
|
|
29
29
|
|
|
30
30
|
### 基本装饰器模式
|
|
31
31
|
|
|
32
|
-
自定义装饰器是一个返回 `MethodDecorator` 的函数。它使用
|
|
32
|
+
自定义装饰器是一个返回 `MethodDecorator` 的函数。它使用 Reflect 元数据 API
|
|
33
33
|
在方法上存储元数据。
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
|
-
import "reflect-metadata";
|
|
37
|
-
|
|
38
36
|
// 1. 定义元数据键(使用 Symbol 确保唯一性)
|
|
39
37
|
export const MY_METADATA_KEY = Symbol("@my-app:my-decorator");
|
|
40
38
|
|
|
@@ -280,8 +278,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
280
278
|
### 存储元数据
|
|
281
279
|
|
|
282
280
|
```typescript
|
|
283
|
-
import "reflect-metadata";
|
|
284
|
-
|
|
285
281
|
const METADATA_KEY = Symbol("my-metadata");
|
|
286
282
|
|
|
287
283
|
// 存储元数据
|
|
@@ -364,7 +360,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
364
360
|
### 示例 1:简单日志拦截器
|
|
365
361
|
|
|
366
362
|
```typescript
|
|
367
|
-
import 'reflect-metadata';
|
|
368
363
|
import { BaseInterceptor } from '@dangao/bun-server';
|
|
369
364
|
import type { Container } from '@dangao/bun-server';
|
|
370
365
|
import type { Context } from '@dangao/bun-server';
|
|
@@ -402,7 +397,6 @@ export class LogInterceptor extends BaseInterceptor {
|
|
|
402
397
|
### 示例 2:限流拦截器
|
|
403
398
|
|
|
404
399
|
```typescript
|
|
405
|
-
import 'reflect-metadata';
|
|
406
400
|
import { BaseInterceptor, HttpException } from '@dangao/bun-server';
|
|
407
401
|
import type { Container } from '@dangao/bun-server';
|
|
408
402
|
import type { Context } from '@dangao/bun-server';
|
package/docs/zh/extensions.md
CHANGED
package/docs/zh/guide.md
CHANGED
package/docs/zh/migration.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dangao/bun-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
|
-
"
|
|
28
|
+
"README.md",
|
|
29
29
|
"LICENSE",
|
|
30
30
|
"src",
|
|
31
31
|
"tests",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"url": "https://github.com/dangaogit/bun-server/issues"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
|
-
"bun": ">=1.3.
|
|
41
|
+
"bun": ">=1.3.10"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"dev": "bun --watch src/index.ts",
|
|
@@ -58,6 +58,6 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"reflect-metadata": "^0.2.2",
|
|
60
60
|
"@dangao/logsmith": "0.1.1",
|
|
61
|
-
"@dangao/nacos-client": "0.1.
|
|
61
|
+
"@dangao/nacos-client": "0.1.1"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/src/core/application.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { ConfigService } from '../config/service';
|
|
|
18
18
|
import { ConfigModule } from '../config/config-module';
|
|
19
19
|
import { CacheModule, CACHE_POST_PROCESSOR_TOKEN } from '../cache';
|
|
20
20
|
import { LoggerManager } from '@dangao/logsmith';
|
|
21
|
+
import { EventModule } from '../events/event-module';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* 应用配置选项
|
|
@@ -44,6 +45,14 @@ export interface ApplicationOptions {
|
|
|
44
45
|
* 默认 true
|
|
45
46
|
*/
|
|
46
47
|
enableSignalHandlers?: boolean;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 是否启用 SO_REUSEPORT
|
|
51
|
+
* 允许多进程绑定同一端口,用于多进程负载均衡
|
|
52
|
+
* 仅 Linux 有效,macOS/Windows 会忽略
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
reusePort?: boolean;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/**
|
|
@@ -102,12 +111,16 @@ export class Application {
|
|
|
102
111
|
// 初始化配置中心集成(在所有模块注册完成后)
|
|
103
112
|
await this.initializeConfigCenter();
|
|
104
113
|
|
|
114
|
+
// 自动初始化事件监听器(如果 EventModule 已注册且启用了 autoScan)
|
|
115
|
+
this.initializeEventListeners();
|
|
116
|
+
|
|
105
117
|
const finalPort = port ?? this.options.port ?? 3000;
|
|
106
118
|
const finalHostname = hostname ?? this.options.hostname;
|
|
107
119
|
|
|
108
120
|
const serverOptions: ServerOptions = {
|
|
109
121
|
port: finalPort,
|
|
110
122
|
hostname: finalHostname,
|
|
123
|
+
reusePort: this.options.reusePort,
|
|
111
124
|
fetch: this.handleRequest.bind(this),
|
|
112
125
|
websocketRegistry: this.websocketRegistry,
|
|
113
126
|
gracefulShutdownTimeout: this.options.gracefulShutdownTimeout,
|
|
@@ -178,6 +191,31 @@ export class Application {
|
|
|
178
191
|
}
|
|
179
192
|
}
|
|
180
193
|
|
|
194
|
+
/**
|
|
195
|
+
* 初始化事件监听器
|
|
196
|
+
* 在所有模块注册完成后调用,自动扫描并注册使用 @OnEvent 装饰器的类
|
|
197
|
+
*/
|
|
198
|
+
private initializeEventListeners(): void {
|
|
199
|
+
const container = this.getContainer();
|
|
200
|
+
|
|
201
|
+
// 检查 EventModule 是否已注册
|
|
202
|
+
const registry = ModuleRegistry.getInstance();
|
|
203
|
+
const eventModuleRef = registry.getModuleRef(EventModule);
|
|
204
|
+
|
|
205
|
+
if (!eventModuleRef) {
|
|
206
|
+
// EventModule 未注册,跳过
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 调用自动初始化
|
|
211
|
+
const initialized = EventModule.autoInitialize(container);
|
|
212
|
+
|
|
213
|
+
if (initialized) {
|
|
214
|
+
const logger = LoggerManager.getLogger();
|
|
215
|
+
logger.debug('[Application] Event listeners initialized automatically');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
181
219
|
/**
|
|
182
220
|
* 停止应用(立即停止,不等待请求完成)
|
|
183
221
|
*/
|
package/src/core/server.ts
CHANGED
|
@@ -33,6 +33,14 @@ export interface ServerOptions {
|
|
|
33
33
|
* 默认 30 秒
|
|
34
34
|
*/
|
|
35
35
|
gracefulShutdownTimeout?: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 是否启用 SO_REUSEPORT
|
|
39
|
+
* 允许多进程绑定同一端口,用于多进程负载均衡
|
|
40
|
+
* 仅 Linux 有效,macOS/Windows 会忽略
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
reusePort?: boolean;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
/**
|
|
@@ -70,6 +78,7 @@ export class BunServer {
|
|
|
70
78
|
this.server = Bun.serve({
|
|
71
79
|
port: this.options.port ?? 3000,
|
|
72
80
|
hostname: this.options.hostname,
|
|
81
|
+
reusePort: this.options.reusePort,
|
|
73
82
|
fetch: (
|
|
74
83
|
request: Request,
|
|
75
84
|
server: Server<WebSocketConnectionData>,
|
|
@@ -102,6 +102,11 @@ export class EventModule {
|
|
|
102
102
|
*/
|
|
103
103
|
private static listenerClasses: Function[] = [];
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* 模块选项
|
|
107
|
+
*/
|
|
108
|
+
private static options: EventModuleOptions & { autoScan?: boolean } = {};
|
|
109
|
+
|
|
105
110
|
/**
|
|
106
111
|
* 创建事件模块
|
|
107
112
|
* @param options - 模块配置
|
|
@@ -121,6 +126,12 @@ export class EventModule {
|
|
|
121
126
|
* ```
|
|
122
127
|
*/
|
|
123
128
|
public static forRoot(options: EventModuleOptions = {}): typeof EventModule {
|
|
129
|
+
// 保存选项(默认启用自动扫描)
|
|
130
|
+
EventModule.options = {
|
|
131
|
+
...options,
|
|
132
|
+
autoScan: options.autoScan ?? true,
|
|
133
|
+
};
|
|
134
|
+
|
|
124
135
|
const providers: ModuleProvider[] = [];
|
|
125
136
|
|
|
126
137
|
// 创建事件发射器服务
|
|
@@ -269,4 +280,101 @@ export class EventModule {
|
|
|
269
280
|
|
|
270
281
|
return undefined;
|
|
271
282
|
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 自动初始化事件监听器
|
|
286
|
+
* 由框架在应用启动时自动调用,扫描所有模块中使用 @OnEvent 装饰器的类并注册
|
|
287
|
+
*
|
|
288
|
+
* @param rootContainer - 根容器
|
|
289
|
+
* @returns 是否成功初始化
|
|
290
|
+
*
|
|
291
|
+
* @internal 此方法由框架内部调用,用户通常不需要手动调用
|
|
292
|
+
*/
|
|
293
|
+
public static autoInitialize(rootContainer: Container): boolean {
|
|
294
|
+
// 检查是否启用自动扫描
|
|
295
|
+
if (EventModule.options.autoScan === false) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 获取 EventEmitter
|
|
300
|
+
const registry = ModuleRegistry.getInstance();
|
|
301
|
+
const eventModuleRef = registry.getModuleRef(EventModule);
|
|
302
|
+
|
|
303
|
+
if (!eventModuleRef) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let eventEmitter: EventEmitter | undefined;
|
|
308
|
+
try {
|
|
309
|
+
eventEmitter = eventModuleRef.container.resolve<EventEmitter>(EVENT_EMITTER_TOKEN);
|
|
310
|
+
} catch {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!eventEmitter) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// 收集所有监听器类
|
|
319
|
+
const listenerClasses = new Set<Function>();
|
|
320
|
+
|
|
321
|
+
// 1. 添加通过 registerListeners 注册的类
|
|
322
|
+
for (const listenerClass of EventModule.listenerClasses) {
|
|
323
|
+
listenerClasses.add(listenerClass);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// 2. 添加通过选项配置的强制包含类
|
|
327
|
+
if (EventModule.options.includeListeners) {
|
|
328
|
+
for (const listenerClass of EventModule.options.includeListeners) {
|
|
329
|
+
listenerClasses.add(listenerClass);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 3. 自动扫描所有模块的 providers,并从对应的模块容器中解析实例
|
|
334
|
+
const shouldAutoScan = EventModule.options.autoScan ?? true;
|
|
335
|
+
if (shouldAutoScan === true) {
|
|
336
|
+
const allModuleRefs = Array.from(registry['moduleRefs'].values());
|
|
337
|
+
|
|
338
|
+
for (const moduleRef of allModuleRefs) {
|
|
339
|
+
for (const provider of moduleRef.metadata.providers) {
|
|
340
|
+
// 提取提供者类
|
|
341
|
+
let providerClass: Function | undefined;
|
|
342
|
+
|
|
343
|
+
if (typeof provider === 'function') {
|
|
344
|
+
providerClass = provider;
|
|
345
|
+
} else if ('useClass' in provider && provider.useClass) {
|
|
346
|
+
providerClass = provider.useClass;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 检查是否是事件监听器类
|
|
350
|
+
if (providerClass && isEventListenerClass(providerClass)) {
|
|
351
|
+
// 检查是否被排除
|
|
352
|
+
const isExcluded = EventModule.options.excludeListeners?.includes(providerClass);
|
|
353
|
+
if (!isExcluded) {
|
|
354
|
+
// 使用模块容器创建 scanner 并注册监听器
|
|
355
|
+
// 这样可以确保解析的实例和控制器中注入的是同一个
|
|
356
|
+
const scanner = new EventListenerScanner(eventEmitter, moduleRef.container);
|
|
357
|
+
scanner.registerListenerClass(providerClass);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// 4. 注册通过选项配置的强制包含类(使用根容器)
|
|
365
|
+
if (EventModule.options.includeListeners) {
|
|
366
|
+
const scanner = new EventListenerScanner(eventEmitter, rootContainer);
|
|
367
|
+
for (const listenerClass of EventModule.options.includeListeners) {
|
|
368
|
+
scanner.registerListenerClass(listenerClass);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// 5. 注册通过 registerListeners 注册的类(使用根容器)
|
|
373
|
+
if (EventModule.listenerClasses.length > 0) {
|
|
374
|
+
const scanner = new EventListenerScanner(eventEmitter, rootContainer);
|
|
375
|
+
scanner.scanAndRegister(EventModule.listenerClasses);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
272
380
|
}
|
package/src/events/types.ts
CHANGED
|
@@ -173,6 +173,25 @@ export interface EventModuleOptions {
|
|
|
173
173
|
* @param payload - 事件负载
|
|
174
174
|
*/
|
|
175
175
|
onError?: (error: Error, event: string | symbol, payload: unknown) => void;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 是否自动扫描和注册事件监听器
|
|
179
|
+
* 当设置为 true 时,框架会在应用启动时自动扫描所有模块中使用 @OnEvent 装饰器的类
|
|
180
|
+
* @default true
|
|
181
|
+
*/
|
|
182
|
+
autoScan?: boolean;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 需要排除的监听器类(不自动注册)
|
|
186
|
+
* 用于在自动扫描时排除某些类
|
|
187
|
+
*/
|
|
188
|
+
excludeListeners?: Function[];
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 额外的监听器类(强制注册)
|
|
192
|
+
* 即使 autoScan 为 false,这些类也会被注册
|
|
193
|
+
*/
|
|
194
|
+
includeListeners?: Function[];
|
|
176
195
|
}
|
|
177
196
|
|
|
178
197
|
/**
|
|
@@ -53,5 +53,39 @@ describe('Application', () => {
|
|
|
53
53
|
const data = await response.json();
|
|
54
54
|
expect(data.error).toBe('Not Found');
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
test('should accept reusePort option', async () => {
|
|
58
|
+
const port = getTestPort();
|
|
59
|
+
app = new Application({ port, reusePort: true });
|
|
60
|
+
await app.listen();
|
|
61
|
+
|
|
62
|
+
const server = app.getServer();
|
|
63
|
+
expect(server).toBeDefined();
|
|
64
|
+
expect(server?.isRunning()).toBe(true);
|
|
65
|
+
|
|
66
|
+
const response = await fetch(`http://localhost:${port}/api/ping`);
|
|
67
|
+
expect(response.status).toBe(404);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('should allow two servers on same port with reusePort (Linux only)', async () => {
|
|
71
|
+
if (process.platform !== 'linux') {
|
|
72
|
+
console.log('Skipping reusePort dual-bind test: only works on Linux');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const port = getTestPort();
|
|
77
|
+
app = new Application({ port, reusePort: true });
|
|
78
|
+
await app.listen();
|
|
79
|
+
|
|
80
|
+
const app2 = new Application({ port, reusePort: true });
|
|
81
|
+
await app2.listen();
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const response = await fetch(`http://localhost:${port}/api/test`);
|
|
85
|
+
expect(response.status).toBe(404);
|
|
86
|
+
} finally {
|
|
87
|
+
await app2.stop();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
56
90
|
});
|
|
57
91
|
|
|
@@ -3,7 +3,6 @@ import { DatabaseModule, DatabaseService, DATABASE_SERVICE_TOKEN } from '../../s
|
|
|
3
3
|
import { Container } from '../../src/di/container';
|
|
4
4
|
import { ModuleRegistry } from '../../src/di/module-registry';
|
|
5
5
|
import { MODULE_METADATA_KEY } from '../../src/di/module';
|
|
6
|
-
import 'reflect-metadata';
|
|
7
6
|
|
|
8
7
|
describe('DatabaseModule', () => {
|
|
9
8
|
let container: Container;
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
} from '../../src/database/orm';
|
|
10
10
|
import { DatabaseService, DATABASE_SERVICE_TOKEN } from '../../src/database';
|
|
11
11
|
import { Container } from '../../src/di/container';
|
|
12
|
-
import 'reflect-metadata';
|
|
13
12
|
|
|
14
13
|
describe('TransactionManager', () => {
|
|
15
14
|
let container: Container;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
-
import 'reflect-metadata';
|
|
3
2
|
|
|
4
3
|
import { handleError } from '../../src/error/handler';
|
|
5
4
|
import { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException } from '../../src/error';
|