@dangao/bun-server 1.9.0 → 1.12.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 +79 -6
- package/dist/cache/cache-module.d.ts +6 -0
- package/dist/cache/cache-module.d.ts.map +1 -1
- package/dist/client/generator.d.ts +16 -0
- package/dist/client/generator.d.ts.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/runtime.d.ts +15 -0
- package/dist/client/runtime.d.ts.map +1 -0
- package/dist/client/types.d.ts +36 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/config/config-module.d.ts +7 -0
- package/dist/config/config-module.d.ts.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/service.d.ts +13 -0
- package/dist/config/service.d.ts.map +1 -1
- package/dist/config/types.d.ts +10 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/core/application.d.ts +7 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/apply-decorators.d.ts +6 -0
- package/dist/core/apply-decorators.d.ts.map +1 -0
- package/dist/core/cluster.d.ts +47 -0
- package/dist/core/cluster.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/server.d.ts +8 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/dashboard/controller.d.ts +55 -0
- package/dist/dashboard/controller.d.ts.map +1 -0
- package/dist/dashboard/dashboard-extension.d.ts +20 -0
- package/dist/dashboard/dashboard-extension.d.ts.map +1 -0
- package/dist/dashboard/dashboard-module.d.ts +13 -0
- package/dist/dashboard/dashboard-module.d.ts.map +1 -0
- package/dist/dashboard/index.d.ts +4 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/types.d.ts +16 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/ui.d.ts +7 -0
- package/dist/dashboard/ui.d.ts.map +1 -0
- package/dist/database/database-module.d.ts +7 -0
- package/dist/database/database-module.d.ts.map +1 -1
- package/dist/debug/debug-module.d.ts +13 -0
- package/dist/debug/debug-module.d.ts.map +1 -0
- package/dist/debug/debug-ui-middleware.d.ts +8 -0
- package/dist/debug/debug-ui-middleware.d.ts.map +1 -0
- package/dist/debug/index.d.ts +5 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/middleware.d.ts +12 -0
- package/dist/debug/middleware.d.ts.map +1 -0
- package/dist/debug/recorder.d.ts +61 -0
- package/dist/debug/recorder.d.ts.map +1 -0
- package/dist/debug/types.d.ts +48 -0
- package/dist/debug/types.d.ts.map +1 -0
- package/dist/debug/ui.d.ts +6 -0
- package/dist/debug/ui.d.ts.map +1 -0
- package/dist/di/async-module.d.ts +49 -0
- package/dist/di/async-module.d.ts.map +1 -0
- package/dist/di/lifecycle.d.ts +49 -0
- package/dist/di/lifecycle.d.ts.map +1 -0
- package/dist/di/module-registry.d.ts +24 -0
- package/dist/di/module-registry.d.ts.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1887 -35
- package/dist/router/route.d.ts +5 -7
- package/dist/router/route.d.ts.map +1 -1
- package/dist/swagger/generator.d.ts +10 -0
- package/dist/swagger/generator.d.ts.map +1 -1
- package/dist/testing/test-client.d.ts +49 -0
- package/dist/testing/test-client.d.ts.map +1 -0
- package/dist/testing/testing-module.d.ts +90 -0
- package/dist/testing/testing-module.d.ts.map +1 -0
- package/dist/websocket/registry.d.ts +1 -6
- package/dist/websocket/registry.d.ts.map +1 -1
- package/docs/async-module.md +59 -0
- package/docs/client-generation.md +100 -0
- package/docs/cluster.md +81 -0
- package/docs/custom-decorators.md +1 -7
- package/docs/dashboard.md +54 -0
- package/docs/debug.md +58 -0
- package/docs/extensions.md +0 -2
- package/docs/guide.md +0 -1
- package/docs/lifecycle.md +72 -0
- package/docs/testing.md +110 -0
- package/docs/zh/async-module.md +98 -0
- package/docs/zh/client-generation.md +92 -0
- package/docs/zh/cluster.md +74 -0
- package/docs/zh/custom-decorators.md +1 -7
- package/docs/zh/dashboard.md +69 -0
- package/docs/zh/debug.md +81 -0
- package/docs/zh/extensions.md +0 -2
- package/docs/zh/guide.md +0 -1
- package/docs/zh/lifecycle.md +87 -0
- package/docs/zh/migration.md +0 -5
- package/docs/zh/testing.md +119 -0
- package/package.json +4 -4
- package/src/cache/cache-module.ts +25 -0
- package/src/client/generator.ts +36 -0
- package/src/client/index.ts +8 -0
- package/src/client/runtime.ts +101 -0
- package/src/client/types.ts +38 -0
- package/src/config/config-module.ts +44 -4
- package/src/config/index.ts +1 -0
- package/src/config/service.ts +50 -0
- package/src/config/types.ts +12 -0
- package/src/core/application.ts +37 -0
- package/src/core/apply-decorators.ts +31 -0
- package/src/core/cluster.ts +143 -0
- package/src/core/index.ts +1 -0
- package/src/core/server.ts +14 -1
- package/src/dashboard/controller.ts +227 -0
- package/src/dashboard/dashboard-extension.ts +26 -0
- package/src/dashboard/dashboard-module.ts +38 -0
- package/src/dashboard/index.ts +3 -0
- package/src/dashboard/types.ts +16 -0
- package/src/dashboard/ui.ts +219 -0
- package/src/database/database-module.ts +20 -0
- package/src/debug/debug-module.ts +70 -0
- package/src/debug/debug-ui-middleware.ts +110 -0
- package/src/debug/index.ts +9 -0
- package/src/debug/middleware.ts +126 -0
- package/src/debug/recorder.ts +141 -0
- package/src/debug/types.ts +49 -0
- package/src/debug/ui.ts +393 -0
- package/src/di/async-module.ts +141 -0
- package/src/di/lifecycle.ts +117 -0
- package/src/di/module-registry.ts +75 -0
- package/src/index.ts +35 -0
- package/src/router/route.ts +20 -20
- package/src/swagger/generator.ts +100 -0
- package/src/testing/test-client.ts +112 -0
- package/src/testing/testing-module.ts +238 -0
- package/src/websocket/registry.ts +3 -16
- 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/client/client-generator.test.ts +142 -0
- 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/core/apply-decorators.test.ts +109 -0
- package/tests/core/cluster.test.ts +32 -0
- package/tests/dashboard/dashboard-module.test.ts +85 -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/debug/debug-module.test.ts +141 -0
- package/tests/di/async-module.test.ts +125 -0
- package/tests/di/container.test.ts +0 -1
- package/tests/di/lifecycle.test.ts +140 -0
- 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/testing/testing-module.test.ts +129 -0
- package/tests/validation/class-validator.test.ts +0 -1
- package/tests/validation/controller-validation.test.ts +0 -1
package/dist/router/route.d.ts
CHANGED
|
@@ -28,23 +28,21 @@ export declare class Route {
|
|
|
28
28
|
*/
|
|
29
29
|
readonly methodName?: string;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* 动态路由匹配用正则(比 URLPattern.exec() 快约 10 倍)
|
|
32
32
|
*/
|
|
33
|
-
private readonly pattern
|
|
33
|
+
private readonly pattern?;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* 动态路由参数名列表
|
|
36
36
|
*/
|
|
37
|
-
private readonly paramNames
|
|
37
|
+
private readonly paramNames?;
|
|
38
38
|
private readonly middlewarePipeline;
|
|
39
39
|
private readonly staticKey?;
|
|
40
40
|
readonly isStatic: boolean;
|
|
41
41
|
constructor(method: HttpMethod, path: string, handler: RouteHandler, middlewares?: Middleware[], controllerClass?: Constructor<unknown>, methodName?: string);
|
|
42
42
|
/**
|
|
43
43
|
* 解析路径,生成匹配模式和参数名列表
|
|
44
|
-
* @param path - 路由路径
|
|
45
|
-
* @returns 匹配模式和参数名列表
|
|
46
44
|
*/
|
|
47
|
-
private parsePath;
|
|
45
|
+
private static parsePath;
|
|
48
46
|
/**
|
|
49
47
|
* 匹配路由
|
|
50
48
|
* @param method - HTTP 方法
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/router/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,qBAAa,KAAK;IAChB;;OAEG;IACH,SAAgB,MAAM,EAAE,UAAU,CAAC;IAEnC;;OAEG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SAAgB,OAAO,EAAE,YAAY,CAAC;IAEtC;;OAEG;IACH,SAAgB,eAAe,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAEvD;;OAEG;IACH,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/router/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,qBAAa,KAAK;IAChB;;OAEG;IACH,SAAgB,MAAM,EAAE,UAAU,CAAC;IAEnC;;OAEG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SAAgB,OAAO,EAAE,YAAY,CAAC;IAEtC;;OAEG;IACH,SAAgB,eAAe,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAEvD;;OAEG;IACH,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAElC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAW;IAEvC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA4B;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,SAAgB,QAAQ,EAAE,OAAO,CAAC;gBAGhC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,WAAW,GAAE,UAAU,EAAO,EAC9B,eAAe,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM;IAmBrB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAYxB;;;;;OAKG;IACI,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU;IAwB1D;;;;OAIG;IACU,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQzD;;OAEG;IACI,YAAY,IAAI,MAAM,GAAG,SAAS;CAG1C"}
|
|
@@ -9,6 +9,16 @@ export declare class SwaggerGenerator {
|
|
|
9
9
|
* 生成 Swagger 文档
|
|
10
10
|
*/
|
|
11
11
|
generate(): SwaggerDocument;
|
|
12
|
+
/**
|
|
13
|
+
* 生成 Markdown 格式的 API 文档
|
|
14
|
+
* 利用 Bun 1.3.8+ 原生 Bun.markdown 内置解析器
|
|
15
|
+
*/
|
|
16
|
+
generateMarkdown(): string;
|
|
17
|
+
/**
|
|
18
|
+
* 生成 Markdown 并渲染为 HTML
|
|
19
|
+
* 利用 Bun.markdown.html() 进行高性能渲染
|
|
20
|
+
*/
|
|
21
|
+
generateMarkdownHtml(): string;
|
|
12
22
|
/**
|
|
13
23
|
* 规范化路径
|
|
14
24
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/swagger/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAmB,MAAM,SAAS,CAAC;AAWhF;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;gBAEtB,OAAO,EAAE,cAAc;IAI1C;;OAEG;IACI,QAAQ,IAAI,eAAe;IAgMlC;;OAEG;IACH,OAAO,CAAC,aAAa;CAatB"}
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/swagger/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAmB,MAAM,SAAS,CAAC;AAWhF;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;gBAEtB,OAAO,EAAE,cAAc;IAI1C;;OAEG;IACI,QAAQ,IAAI,eAAe;IAgMlC;;;OAGG;IACI,gBAAgB,IAAI,MAAM;IAuFjC;;;OAGG;IACI,oBAAoB,IAAI,MAAM;IAKrC;;OAEG;IACH,OAAO,CAAC,aAAa;CAatB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Application } from '../core/application';
|
|
2
|
+
interface RequestOptions {
|
|
3
|
+
headers?: Record<string, string>;
|
|
4
|
+
body?: unknown;
|
|
5
|
+
query?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
interface TestResponse {
|
|
8
|
+
status: number;
|
|
9
|
+
headers: Headers;
|
|
10
|
+
body: unknown;
|
|
11
|
+
text: string;
|
|
12
|
+
ok: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* HTTP 测试客户端
|
|
16
|
+
* 基于 fetch API,提供简洁的 HTTP 请求方法
|
|
17
|
+
*/
|
|
18
|
+
export declare class TestHttpClient {
|
|
19
|
+
private readonly baseUrl;
|
|
20
|
+
private readonly app;
|
|
21
|
+
constructor(baseUrl: string, app: Application);
|
|
22
|
+
/**
|
|
23
|
+
* 发送 GET 请求
|
|
24
|
+
*/
|
|
25
|
+
get(path: string, options?: RequestOptions): Promise<TestResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* 发送 POST 请求
|
|
28
|
+
*/
|
|
29
|
+
post(path: string, options?: RequestOptions): Promise<TestResponse>;
|
|
30
|
+
/**
|
|
31
|
+
* 发送 PUT 请求
|
|
32
|
+
*/
|
|
33
|
+
put(path: string, options?: RequestOptions): Promise<TestResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* 发送 DELETE 请求
|
|
36
|
+
*/
|
|
37
|
+
delete(path: string, options?: RequestOptions): Promise<TestResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* 发送 PATCH 请求
|
|
40
|
+
*/
|
|
41
|
+
patch(path: string, options?: RequestOptions): Promise<TestResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* 关闭测试服务器
|
|
44
|
+
*/
|
|
45
|
+
close(): Promise<void>;
|
|
46
|
+
private request;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=test-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-client.d.ts","sourceRoot":"","sources":["../../src/testing/test-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;CACb;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;gBAEf,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW;IAKpD;;OAEG;IACU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/E;;OAEG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhF;;OAEG;IACU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/E;;OAEG;IACU,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAIlF;;OAEG;IACU,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAIjF;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAIrB,OAAO;CAwCtB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Application, type ApplicationOptions } from '../core/application';
|
|
3
|
+
import { Container } from '../di/container';
|
|
4
|
+
import { type ModuleMetadata, type ModuleProvider, type ProviderToken } from '../di/module';
|
|
5
|
+
import type { Constructor } from '../core/types';
|
|
6
|
+
import { TestHttpClient } from './test-client';
|
|
7
|
+
interface ProviderOverride {
|
|
8
|
+
token: ProviderToken;
|
|
9
|
+
useValue?: unknown;
|
|
10
|
+
useClass?: Constructor<unknown>;
|
|
11
|
+
useFactory?: () => unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 测试模块构建器
|
|
15
|
+
* 提供流畅的 API 来创建测试用的隔离模块环境
|
|
16
|
+
*/
|
|
17
|
+
export declare class TestingModuleBuilder {
|
|
18
|
+
private readonly metadata;
|
|
19
|
+
private readonly overrides;
|
|
20
|
+
constructor(metadata: ModuleMetadata);
|
|
21
|
+
/**
|
|
22
|
+
* 覆盖指定 provider
|
|
23
|
+
* @param token - 要覆盖的 provider token
|
|
24
|
+
*/
|
|
25
|
+
overrideProvider(token: ProviderToken): ProviderOverrideBuilder;
|
|
26
|
+
/**
|
|
27
|
+
* 编译测试模块,返回可用的 TestingModule 实例
|
|
28
|
+
*/
|
|
29
|
+
compile(): Promise<TestingModule>;
|
|
30
|
+
private buildProviders;
|
|
31
|
+
}
|
|
32
|
+
declare class ProviderOverrideBuilder {
|
|
33
|
+
private readonly builder;
|
|
34
|
+
private readonly token;
|
|
35
|
+
constructor(builder: TestingModuleBuilder, token: ProviderToken);
|
|
36
|
+
/**
|
|
37
|
+
* 使用固定值覆盖
|
|
38
|
+
*/
|
|
39
|
+
useValue(value: unknown): TestingModuleBuilder;
|
|
40
|
+
/**
|
|
41
|
+
* 使用替代类覆盖
|
|
42
|
+
*/
|
|
43
|
+
useClass(cls: Constructor<unknown>): TestingModuleBuilder;
|
|
44
|
+
/**
|
|
45
|
+
* 使用工厂函数覆盖
|
|
46
|
+
*/
|
|
47
|
+
useFactory(factory: () => unknown): TestingModuleBuilder;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 编译后的测试模块
|
|
51
|
+
* 提供 DI 容器访问和 HTTP 测试客户端创建
|
|
52
|
+
*/
|
|
53
|
+
export declare class TestingModule {
|
|
54
|
+
private readonly metadata;
|
|
55
|
+
private readonly providers;
|
|
56
|
+
private readonly overrides;
|
|
57
|
+
private app?;
|
|
58
|
+
private container?;
|
|
59
|
+
constructor(metadata: ModuleMetadata, providers: ModuleProvider[], overrides: ProviderOverride[]);
|
|
60
|
+
/**
|
|
61
|
+
* 从容器中获取 provider 实例
|
|
62
|
+
*/
|
|
63
|
+
get<T>(token: Constructor<T> | string | symbol): T;
|
|
64
|
+
/**
|
|
65
|
+
* 创建一个 Application 实例并注册所有 providers、controllers
|
|
66
|
+
* @param options - 应用配置
|
|
67
|
+
*/
|
|
68
|
+
createApplication(options?: ApplicationOptions): Application;
|
|
69
|
+
/**
|
|
70
|
+
* 创建 HTTP 测试客户端
|
|
71
|
+
* 自动启动应用,获取随机端口,返回 TestHttpClient
|
|
72
|
+
*/
|
|
73
|
+
createHttpClient(options?: ApplicationOptions): Promise<TestHttpClient>;
|
|
74
|
+
/**
|
|
75
|
+
* 获取 DI 容器
|
|
76
|
+
*/
|
|
77
|
+
getContainer(): Container;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 测试工具入口
|
|
81
|
+
*/
|
|
82
|
+
export declare class Test {
|
|
83
|
+
/**
|
|
84
|
+
* 创建测试模块
|
|
85
|
+
* @param metadata - 模块元数据
|
|
86
|
+
*/
|
|
87
|
+
static createTestingModule(metadata: ModuleMetadata): TestingModuleBuilder;
|
|
88
|
+
}
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=testing-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing-module.d.ts","sourceRoot":"","sources":["../../src/testing/testing-module.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,OAAO,EAAuB,KAAK,cAAc,EAAoB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACnI,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,UAAU,gBAAgB;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;gBAEjC,QAAQ,EAAE,cAAc;IAI3C;;;OAGG;IACI,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,uBAAuB;IAItE;;OAEG;IACU,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;IAU9C,OAAO,CAAC,cAAc;CA0CvB;AAED,cAAM,uBAAuB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;gBAEnB,OAAO,EAAE,oBAAoB,EAAE,KAAK,EAAE,aAAa;IAKtE;;OAEG;IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB;IAKrD;;OAEG;IACI,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,oBAAoB;IAKhE;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,oBAAoB;CAIhE;AAED;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,GAAG,CAAC,CAAc;IAC1B,OAAO,CAAC,SAAS,CAAC,CAAY;gBAG5B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,cAAc,EAAE,EAC3B,SAAS,EAAE,gBAAgB,EAAE;IAO/B;;OAEG;IACI,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC;IAIzD;;;OAGG;IACI,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW;IA2CvE;;;OAGG;IACU,gBAAgB,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,cAAc,CAAC;IAQxF;;OAEG;IACI,YAAY,IAAI,SAAS;CAKjC;AAED;;GAEG;AACH,qBAAa,IAAI;IACf;;;OAGG;WACW,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,oBAAoB;CAGlF"}
|
|
@@ -15,12 +15,7 @@ export declare class WebSocketGatewayRegistry {
|
|
|
15
15
|
private readonly dynamicGateways;
|
|
16
16
|
private constructor();
|
|
17
17
|
static getInstance(): WebSocketGatewayRegistry;
|
|
18
|
-
|
|
19
|
-
* 解析路径,生成匹配模式和参数名列表
|
|
20
|
-
* @param path - 路由路径
|
|
21
|
-
* @returns 匹配模式和参数名列表
|
|
22
|
-
*/
|
|
23
|
-
private parsePath;
|
|
18
|
+
private static parsePath;
|
|
24
19
|
register(gatewayClass: Constructor<unknown>): void;
|
|
25
20
|
/**
|
|
26
21
|
* 检查是否有匹配的网关(支持动态路径匹配)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/websocket/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAO3C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAehD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IACjE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2B;IAE3D,OAAO;WAIO,WAAW,IAAI,wBAAwB;IAOrD
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/websocket/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAO3C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAehD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IACjE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2B;IAE3D,OAAO;WAIO,WAAW,IAAI,wBAAwB;IAOrD,OAAO,CAAC,MAAM,CAAC,SAAS;IAYjB,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAoCzD;;;;OAIG;IACI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAcjC,KAAK,IAAI,IAAI;IAMpB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAoBlB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;;;;;OAMG;YACW,aAAa;IA0Gd,UAAU,CAAC,EAAE,EAAE,eAAe,CAAC,uBAAuB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAcvE,aAAa,CACxB,EAAE,EAAE,eAAe,CAAC,uBAAuB,CAAC,EAC5C,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,GAC9C,OAAO,CAAC,IAAI,CAAC;IAcH,WAAW,CACtB,EAAE,EAAE,eAAe,CAAC,uBAAuB,CAAC,EAC5C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;CAQjB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Async Module Configuration
|
|
2
|
+
|
|
3
|
+
Some modules support `forRootAsync()` for configuration that depends on asynchronous sources (remote config, secrets, database lookups). The async factory runs during `Application.listen()` before the server starts.
|
|
4
|
+
|
|
5
|
+
## AsyncModuleOptions<T>
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
interface AsyncModuleOptions<T> {
|
|
9
|
+
imports?: ModuleClass[]; // Modules providing inject dependencies
|
|
10
|
+
inject?: ProviderToken[]; // Tokens to inject into useFactory
|
|
11
|
+
useFactory: (...deps: unknown[]) => T | Promise<T>;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Available Modules
|
|
16
|
+
|
|
17
|
+
- **ConfigModule** – Load config from remote sources
|
|
18
|
+
- **DatabaseModule** – Get DB options from ConfigService or secrets
|
|
19
|
+
- **CacheModule** – Get cache config asynchronously
|
|
20
|
+
|
|
21
|
+
## Example: ConfigModule.forRootAsync
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
@Module({
|
|
25
|
+
imports: [
|
|
26
|
+
ConfigModule.forRootAsync({
|
|
27
|
+
useFactory: async () => {
|
|
28
|
+
const remoteConfig = await loadRemoteConfig();
|
|
29
|
+
return { defaultConfig: remoteConfig };
|
|
30
|
+
},
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
controllers: [AppController],
|
|
34
|
+
})
|
|
35
|
+
class AppModule {}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Example: DatabaseModule.forRootAsync with ConfigService
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { ConfigModule, CONFIG_SERVICE_TOKEN } from '@dangao/bun-server';
|
|
42
|
+
|
|
43
|
+
@Module({
|
|
44
|
+
imports: [
|
|
45
|
+
ConfigModule.forRoot({ defaultConfig: { db: { url: '...' } } }),
|
|
46
|
+
DatabaseModule.forRootAsync({
|
|
47
|
+
imports: [ConfigModule],
|
|
48
|
+
inject: [CONFIG_SERVICE_TOKEN],
|
|
49
|
+
useFactory: (config: ConfigService) => ({
|
|
50
|
+
url: config.get<string>('db.url'),
|
|
51
|
+
// ...other options
|
|
52
|
+
}),
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
})
|
|
56
|
+
class AppModule {}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The `useFactory` receives resolved dependencies in the order of `inject`. Async providers are initialized sequentially during `listen()`.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Type-Safe Client Generation
|
|
2
|
+
|
|
3
|
+
Generate a type-safe API client from your server's route manifest. The client is grouped by controller name and mirrors your controller methods.
|
|
4
|
+
|
|
5
|
+
## Workflow
|
|
6
|
+
|
|
7
|
+
1. Register controllers and start the application (or at least register routes)
|
|
8
|
+
2. Call `ClientGenerator.generate()` to extract the route manifest
|
|
9
|
+
3. Call `createClient(manifest, config)` to build the client
|
|
10
|
+
|
|
11
|
+
## ClientGenerator.generate()
|
|
12
|
+
|
|
13
|
+
Extracts route metadata from the current `RouteRegistry`:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const manifest = ClientGenerator.generate();
|
|
17
|
+
// { routes: [{ method, path, controllerName, methodName }, ...] }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use `ClientGenerator.generateJSON()` for a JSON string.
|
|
21
|
+
|
|
22
|
+
## createClient(manifest, config)
|
|
23
|
+
|
|
24
|
+
Creates an API client:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
const client = createClient(manifest, {
|
|
28
|
+
baseUrl: 'http://localhost:3000',
|
|
29
|
+
headers: { 'X-API-Key': 'secret' },
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Client Structure
|
|
34
|
+
|
|
35
|
+
The client is grouped by controller name (with `Controller` suffix removed and first letter lowercased). Each method maps to a function:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
client.user.listUsers(); // GET /api/users/
|
|
39
|
+
client.user.getUser({ params: { id: '1' } }); // GET /api/users/:id
|
|
40
|
+
client.user.createUser({ body: { name: 'Alice' } }); // POST /api/users/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## ClientRequestOptions
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
{
|
|
47
|
+
params?: Record<string, string>; // Path params (:id -> params.id)
|
|
48
|
+
query?: Record<string, string>; // Query string
|
|
49
|
+
body?: unknown; // Request body (JSON)
|
|
50
|
+
headers?: Record<string, string>; // Extra headers
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Full Example
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
Application,
|
|
59
|
+
Controller,
|
|
60
|
+
GET,
|
|
61
|
+
POST,
|
|
62
|
+
Param,
|
|
63
|
+
Body,
|
|
64
|
+
Module,
|
|
65
|
+
ClientGenerator,
|
|
66
|
+
createClient,
|
|
67
|
+
} from '@dangao/bun-server';
|
|
68
|
+
|
|
69
|
+
@Controller('/api/users')
|
|
70
|
+
class UserController {
|
|
71
|
+
@GET('/')
|
|
72
|
+
public listUsers(): object {
|
|
73
|
+
return [{ id: '1', name: 'Alice' }];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@GET('/:id')
|
|
77
|
+
public getUser(@Param('id') id: string): object {
|
|
78
|
+
return { id, name: 'Alice' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@POST('/')
|
|
82
|
+
public createUser(@Body() body: unknown): object {
|
|
83
|
+
return { ...(body as object), id: '3' };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Module({ controllers: [UserController] })
|
|
88
|
+
class AppModule {}
|
|
89
|
+
|
|
90
|
+
const app = new Application({ port: 3001 });
|
|
91
|
+
app.registerModule(AppModule);
|
|
92
|
+
await app.listen();
|
|
93
|
+
|
|
94
|
+
const manifest = ClientGenerator.generate();
|
|
95
|
+
const client = createClient(manifest, { baseUrl: 'http://localhost:3001' });
|
|
96
|
+
|
|
97
|
+
const users = await client.user.listUsers();
|
|
98
|
+
const user = await client.user.getUser({ params: { id: '42' } });
|
|
99
|
+
const created = await client.user.createUser({ body: { name: 'Charlie' } });
|
|
100
|
+
```
|
package/docs/cluster.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Zero-Config Cluster
|
|
2
|
+
|
|
3
|
+
`ClusterManager` spawns multiple worker processes that share a single port via SO_REUSEPORT. Each worker runs your application; the master process monitors and restarts crashed workers.
|
|
4
|
+
|
|
5
|
+
## ClusterManager Class
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const manager = new ClusterManager({
|
|
9
|
+
workers: 'auto' | number, // 'auto' = CPU cores
|
|
10
|
+
scriptPath: import.meta.path,
|
|
11
|
+
port: 3000,
|
|
12
|
+
hostname?: string,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
manager.start();
|
|
16
|
+
await manager.stop();
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Static Methods
|
|
20
|
+
|
|
21
|
+
- **ClusterManager.isWorker()**: Returns `true` in worker processes; `false` in master
|
|
22
|
+
- **ClusterManager.getWorkerId()**: Returns worker index (0, 1, ...) in workers; `-1` in master
|
|
23
|
+
|
|
24
|
+
## Master/Worker Pattern
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
if (!ClusterManager.isWorker()) {
|
|
28
|
+
// Master: spawn workers
|
|
29
|
+
const manager = new ClusterManager({
|
|
30
|
+
workers: 'auto',
|
|
31
|
+
scriptPath: import.meta.path,
|
|
32
|
+
port: PORT,
|
|
33
|
+
});
|
|
34
|
+
manager.start();
|
|
35
|
+
|
|
36
|
+
process.on('SIGINT', async () => {
|
|
37
|
+
await manager.stop();
|
|
38
|
+
process.exit(0);
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
// Worker: run app
|
|
42
|
+
const app = new Application({
|
|
43
|
+
port: PORT,
|
|
44
|
+
reusePort: true,
|
|
45
|
+
enableSignalHandlers: true,
|
|
46
|
+
});
|
|
47
|
+
app.registerModule(WorkerModule);
|
|
48
|
+
await app.listen();
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Linux-Only: reusePort
|
|
53
|
+
|
|
54
|
+
SO_REUSEPORT works on Linux. On macOS and Windows it is ignored; the app may still run but only one worker will bind the port.
|
|
55
|
+
|
|
56
|
+
## Example
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const PORT = Number(process.env.PORT ?? 3300);
|
|
60
|
+
|
|
61
|
+
if (!ClusterManager.isWorker()) {
|
|
62
|
+
const manager = new ClusterManager({
|
|
63
|
+
workers: process.env.WORKERS ? Number(process.env.WORKERS) : 'auto',
|
|
64
|
+
scriptPath: import.meta.path,
|
|
65
|
+
port: PORT,
|
|
66
|
+
});
|
|
67
|
+
manager.start();
|
|
68
|
+
process.on('SIGINT', () => manager.stop().then(() => process.exit(0)));
|
|
69
|
+
} else {
|
|
70
|
+
@Controller('/api')
|
|
71
|
+
class PerfController {
|
|
72
|
+
@GET('/ping')
|
|
73
|
+
public ping(): object {
|
|
74
|
+
return { pong: true, worker: ClusterManager.getWorkerId() };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const app = new Application({ port: PORT, reusePort: true });
|
|
78
|
+
app.registerModule(WorkerModule);
|
|
79
|
+
await app.listen();
|
|
80
|
+
}
|
|
81
|
+
```
|
|
@@ -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';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Dashboard Module
|
|
2
|
+
|
|
3
|
+
The Dashboard Module provides a monitoring Web UI with system metrics, route listing, and health status.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
DashboardModule.forRoot({
|
|
9
|
+
path: '/_dashboard', // default
|
|
10
|
+
auth: { username: 'admin', password: 'admin' },
|
|
11
|
+
})
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- **path**: Base path for the dashboard (default `/_dashboard`)
|
|
15
|
+
- **auth**: Optional Basic Auth. If omitted, the dashboard is unauthenticated.
|
|
16
|
+
|
|
17
|
+
## Endpoints
|
|
18
|
+
|
|
19
|
+
| Path | Description |
|
|
20
|
+
|------|--------------|
|
|
21
|
+
| `/{path}` | Dashboard UI (HTML) |
|
|
22
|
+
| `/{path}/api/system` | System info (uptime, memory, platform, Bun version) |
|
|
23
|
+
| `/{path}/api/routes` | Registered routes (method, path, controller, methodName) |
|
|
24
|
+
| `/{path}/api/health` | Health check results (if HealthModule is used) |
|
|
25
|
+
|
|
26
|
+
## Basic Auth
|
|
27
|
+
|
|
28
|
+
When `auth` is set, all dashboard endpoints require Basic Auth. The browser will prompt for credentials.
|
|
29
|
+
|
|
30
|
+
## UI Description
|
|
31
|
+
|
|
32
|
+
The dashboard is a dark-themed single-page UI with:
|
|
33
|
+
|
|
34
|
+
- **Header**: "Bun Server Dashboard" and a short description
|
|
35
|
+
- **Cards**: System (uptime, memory, platform), Routes (count and list), Health (status and details)
|
|
36
|
+
- **Layout**: Responsive grid of cards with monospace values
|
|
37
|
+
- **Links**: Quick links to system, routes, and health API endpoints
|
|
38
|
+
|
|
39
|
+
## Example
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
@Module({
|
|
43
|
+
imports: [
|
|
44
|
+
DashboardModule.forRoot({
|
|
45
|
+
path: '/_dashboard',
|
|
46
|
+
auth: { username: 'admin', password: 'admin' },
|
|
47
|
+
}),
|
|
48
|
+
],
|
|
49
|
+
controllers: [AppController],
|
|
50
|
+
})
|
|
51
|
+
class AppModule {}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Access at `http://localhost:3000/_dashboard` (credentials: admin/admin).
|
package/docs/debug.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Debug & Request Replay Module
|
|
2
|
+
|
|
3
|
+
The Debug Module records HTTP requests in development and provides a UI to inspect and replay them.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
DebugModule.forRoot({
|
|
9
|
+
enabled: true, // default
|
|
10
|
+
maxRecords: 500, // default, ring buffer size
|
|
11
|
+
recordBody: true, // default, capture request/response bodies
|
|
12
|
+
path: '/_debug', // default
|
|
13
|
+
})
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Recorded Data
|
|
17
|
+
|
|
18
|
+
Each `RequestRecord` includes:
|
|
19
|
+
|
|
20
|
+
- **id**: Unique record ID
|
|
21
|
+
- **timestamp**: Request time
|
|
22
|
+
- **request**: method, path, headers, body (if `recordBody`)
|
|
23
|
+
- **response**: status, headers, bodySize
|
|
24
|
+
- **timing**: total duration (ms)
|
|
25
|
+
- **metadata**: matchedRoute, controller, methodName
|
|
26
|
+
|
|
27
|
+
## Debug UI Endpoints
|
|
28
|
+
|
|
29
|
+
| Path | Method | Description |
|
|
30
|
+
|------|--------|-------------|
|
|
31
|
+
| `/{path}` | GET | Debug UI (HTML) |
|
|
32
|
+
| `/{path}/api/records` | GET | List all records |
|
|
33
|
+
| `/{path}/api/records` | DELETE | Clear all records |
|
|
34
|
+
| `/{path}/api/records/:id` | GET | Get single record |
|
|
35
|
+
| `/{path}/api/replay/:id` | POST | Replay a request |
|
|
36
|
+
|
|
37
|
+
## Request Replay
|
|
38
|
+
|
|
39
|
+
`POST /_debug/api/replay/:id` replays the recorded request against the current server. The response includes `ok`, `status`, `body`, or `error` on failure.
|
|
40
|
+
|
|
41
|
+
## Example
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
@Module({
|
|
45
|
+
imports: [
|
|
46
|
+
DebugModule.forRoot({
|
|
47
|
+
enabled: true,
|
|
48
|
+
maxRecords: 100,
|
|
49
|
+
recordBody: true,
|
|
50
|
+
path: '/_debug',
|
|
51
|
+
}),
|
|
52
|
+
],
|
|
53
|
+
controllers: [AppController],
|
|
54
|
+
})
|
|
55
|
+
class AppModule {}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Visit `http://localhost:3000/_debug` to view recorded requests and replay them.
|
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