@dangao/bun-server 0.1.4 → 0.1.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/auth/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAO1B;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,eAAe,CAU7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,UAAU,GAAG,SAAS,CAGxB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAGlF;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAMT"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/auth/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAO1B;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,eAAe,CAU7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,UAAU,GAAG,SAAS,CAGxB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAOlF;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAMT"}
@@ -0,0 +1,14 @@
1
+ import { type ConfigModuleOptions } from './types';
2
+ export declare class ConfigModule {
3
+ /**
4
+ * 创建配置模块
5
+ * @param options - 模块配置
6
+ */
7
+ static forRoot(options?: ConfigModuleOptions): typeof ConfigModule;
8
+ /**
9
+ * 获取环境变量快照
10
+ * 方便测试和未来扩展(如 .env 文件解析)
11
+ */
12
+ private static snapshotEnv;
13
+ }
14
+ //# sourceMappingURL=config-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-module.d.ts","sourceRoot":"","sources":["../../src/config/config-module.ts"],"names":[],"mappings":"AAGA,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEzE,qBAGa,YAAY;IACvB;;;OAGG;WACW,OAAO,CACnB,OAAO,GAAE,mBAAwB,GAChC,OAAO,YAAY;IA+CtB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;CAO3B"}
@@ -0,0 +1,4 @@
1
+ export { ConfigModule } from './config-module';
2
+ export { ConfigService } from './service';
3
+ export { CONFIG_SERVICE_TOKEN, type ConfigModuleOptions, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,GACzB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 配置服务
3
+ * 提供类型安全的配置访问能力
4
+ */
5
+ export declare class ConfigService<TConfig extends Record<string, unknown> = Record<string, unknown>> {
6
+ private readonly config;
7
+ private readonly namespace?;
8
+ constructor(config: TConfig, namespace?: string);
9
+ /**
10
+ * 获取完整配置对象
11
+ */
12
+ getAll(): TConfig;
13
+ /**
14
+ * 获取配置值(支持点号路径)
15
+ * @param key - 配置键(如 "db.host")
16
+ * @param defaultValue - 默认值(可选)
17
+ */
18
+ get<T = unknown>(key: string, defaultValue?: T): T | undefined;
19
+ /**
20
+ * 获取必需的配置值,如果不存在则抛出错误
21
+ * @param key - 配置键
22
+ */
23
+ getRequired<T = unknown>(key: string): T;
24
+ /**
25
+ * 创建带命名空间的 ConfigService 视图
26
+ * @param namespace - 命名空间前缀
27
+ */
28
+ withNamespace(namespace: string): ConfigService<TConfig>;
29
+ private applyNamespace;
30
+ private getValueByPath;
31
+ }
32
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/config/service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,aAAa,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1F,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;gBAEjB,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM;IAKtD;;OAEG;IACI,MAAM,IAAI,OAAO;IAIxB;;;;OAIG;IACI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IASrE;;;OAGG;IACI,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC;IAQ/C;;;OAGG;IACI,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC;IAI/D,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,cAAc;CAuBvB"}
@@ -0,0 +1,22 @@
1
+ export interface ConfigModuleOptions<TConfig extends Record<string, unknown> = Record<string, unknown>> {
2
+ /**
3
+ * 默认配置对象(最低优先级)
4
+ */
5
+ defaultConfig?: Partial<TConfig>;
6
+ /**
7
+ * 从环境变量加载配置
8
+ * @param env - process.env 快照
9
+ */
10
+ load?: (env: Record<string, string | undefined>) => Partial<TConfig>;
11
+ /**
12
+ * 配置验证函数(可抛出错误)
13
+ * 可用于集成 class-validator 风格的校验逻辑
14
+ */
15
+ validate?: (config: TConfig) => void;
16
+ /**
17
+ * 命名空间前缀,用于逻辑分组(可选)
18
+ */
19
+ namespace?: string;
20
+ }
21
+ export declare const CONFIG_SERVICE_TOKEN: unique symbol;
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpG;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjC;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAErE;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAErC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB,eAA8C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../src/core/application.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsB,MAAM,UAAU,CAAC;AAKzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,CAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2B;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;gBAEtC,OAAO,GAAE,kBAAuB;IAcnD;;;OAGG;IACI,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAIxC;;OAEG;IACI,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAgBrD;;OAEG;IACI,IAAI,IAAI,IAAI;IAInB;;;;OAIG;YACW,aAAa;IAsB3B;;;OAGG;IACI,kBAAkB,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAKtE;;;OAGG;IACI,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAgBrD;;;OAGG;IACI,wBAAwB,CAAC,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAIzE;;;OAGG;IACI,iBAAiB,CAAC,SAAS,EAAE,oBAAoB,GAAG,IAAI;IAK/D;;;OAGG;IACI,SAAS,IAAI,SAAS,GAAG,SAAS;IAIzC;;;OAGG;IACI,YAAY;CAGpB"}
1
+ {"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../src/core/application.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsB,MAAM,UAAU,CAAC;AAKzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,CAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2B;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;gBAEtC,OAAO,GAAE,kBAAuB;IAcnD;;;OAGG;IACI,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAIxC;;OAEG;IACI,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAgBrD;;OAEG;IACI,IAAI,IAAI,IAAI;IAInB;;;;OAIG;YACW,aAAa;IA2B3B;;;OAGG;IACI,kBAAkB,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAKtE;;;OAGG;IACI,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAgBrD;;;OAGG;IACI,wBAAwB,CAAC,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAIzE;;;OAGG;IACI,iBAAiB,CAAC,SAAS,EAAE,oBAAoB,GAAG,IAAI;IAK/D;;;OAGG;IACI,SAAS,IAAI,SAAS,GAAG,SAAS;IAIzC;;;OAGG;IACI,YAAY;CAGpB"}
@@ -0,0 +1,27 @@
1
+ import type { HealthIndicator, HealthStatus } from './types';
2
+ import type { HealthModuleOptions } from './types';
3
+ /**
4
+ * 健康检查控制器
5
+ *
6
+ * 提供 `/health` 和 `/ready` 两个端点:
7
+ * - /health:存活检查(liveness)
8
+ * - /ready:就绪检查(readiness)
9
+ */
10
+ export declare class HealthController {
11
+ private readonly indicators;
12
+ private readonly options?;
13
+ constructor(indicators?: HealthIndicator[], options?: HealthModuleOptions | undefined);
14
+ /**
15
+ * 存活检查
16
+ */
17
+ health(): Promise<HealthStatus>;
18
+ /**
19
+ * 就绪检查
20
+ */
21
+ ready(): Promise<HealthStatus>;
22
+ /**
23
+ * 执行所有健康检查指示器
24
+ */
25
+ private checkIndicators;
26
+ }
27
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/health/controller.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAEf,YAAY,EACb,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGnD;;;;;;GAMG;AACH,qBACa,gBAAgB;IAGzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAFR,UAAU,GAAE,eAAe,EAAO,EAElC,OAAO,CAAC,EAAE,mBAAmB,YAAA;IAGhD;;OAEG;IAEU,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAI5C;;OAEG;IAEU,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC;IAI3C;;OAEG;YACW,eAAe;CA0B9B"}
@@ -0,0 +1,9 @@
1
+ import type { HealthModuleOptions } from './types';
2
+ export declare class HealthModule {
3
+ /**
4
+ * 创建健康检查模块
5
+ * @param options - 模块配置
6
+ */
7
+ static forRoot(options?: HealthModuleOptions): typeof HealthModule;
8
+ }
9
+ //# sourceMappingURL=health-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-module.d.ts","sourceRoot":"","sources":["../../src/health/health-module.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAmB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGpE,qBAIa,YAAY;IACvB;;;OAGG;WACW,OAAO,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,YAAY;CAiC9E"}
@@ -0,0 +1,4 @@
1
+ export { HealthModule } from './health-module';
2
+ export { HealthController } from './controller';
3
+ export { HEALTH_INDICATORS_TOKEN, HEALTH_OPTIONS_TOKEN, type HealthIndicator, type HealthIndicatorResult, type HealthStatus, type HealthModuleOptions, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/health/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,mBAAmB,GACzB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,22 @@
1
+ export declare const HEALTH_INDICATORS_TOKEN: unique symbol;
2
+ export declare const HEALTH_OPTIONS_TOKEN: unique symbol;
3
+ export type HealthStatusValue = 'up' | 'down';
4
+ export interface HealthIndicatorResult {
5
+ status: HealthStatusValue;
6
+ details?: Record<string, unknown>;
7
+ }
8
+ export interface HealthIndicator {
9
+ name: string;
10
+ check(): Promise<HealthIndicatorResult> | HealthIndicatorResult;
11
+ }
12
+ export interface HealthStatus {
13
+ status: HealthStatusValue;
14
+ details: Record<string, HealthIndicatorResult>;
15
+ }
16
+ export interface HealthModuleOptions {
17
+ /**
18
+ * 健康检查指示器列表
19
+ */
20
+ indicators?: HealthIndicator[];
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/health/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,eAAiD,CAAC;AACtF,eAAO,MAAM,oBAAoB,eAA8C,CAAC;AAEhF,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,qBAAqB,CAAC,GAAG,qBAAqB,CAAC;CACjE;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;CAChC"}
package/dist/index.d.ts CHANGED
@@ -21,6 +21,8 @@ export { WebSocketGateway, OnOpen, OnMessage, OnClose, WebSocketGatewayRegistry,
21
21
  export { LoggerExtension, LoggerModule, LogLevel, LOGGER_TOKEN, type Logger, type LoggerOptions, type LoggerModuleOptions, type LogEntry, } from './extensions';
22
22
  export { SwaggerExtension, SwaggerModule, SwaggerGenerator, createSwaggerUIMiddleware, ApiTags, ApiOperation, ApiParam, ApiBody, ApiResponse, type SwaggerOptions, type SwaggerModuleOptions, type SwaggerDocument, type ApiOperationMetadata, type ApiParamMetadata, type ApiBodyMetadata, type ApiResponseMetadata, } from './swagger';
23
23
  export { SecurityModule, SecurityContextHolder, AuthenticationManager, RoleBasedAccessDecisionManager, JwtAuthenticationProvider, OAuth2AuthenticationProvider, createSecurityFilter, type SecurityModuleConfig, type SecurityConfig, type SecurityContext, type Authentication, type AuthenticationProvider, type AuthenticationRequest, type Principal, type Credentials, type AccessDecisionManager, } from './security';
24
+ export { ConfigModule, ConfigService, CONFIG_SERVICE_TOKEN, type ConfigModuleOptions, } from './config';
25
+ export { HealthModule, type HealthIndicator, type HealthIndicatorResult, type HealthStatus, type HealthModuleOptions, HEALTH_INDICATORS_TOKEN, HEALTH_OPTIONS_TOKEN, } from './health';
24
26
  export { JWTUtil, OAuth2Service, OAuth2Controller, Auth, getAuthMetadata, requiresAuth, checkRoles, OAUTH2_SERVICE_TOKEN, JWT_UTIL_TOKEN, type JWTConfig, type JWTPayload, type OAuth2Client, type OAuth2AuthorizationRequest, type OAuth2TokenRequest, type OAuth2TokenResponse, type UserInfo, type AuthContext, type AuthConfig, } from './auth';
25
27
  export { PerformanceHarness, StressTester, type BenchmarkResult, type StressResult, } from './testing/harness';
26
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACpE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvG,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EACL,MAAM,EACN,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,sBAAsB,EACtB,8BAA8B,EAC9B,6BAA6B,EAC7B,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,UAAU,EACV,SAAS,EACT,eAAe,EACf,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,4BAA4B,EAC5B,uBAAuB,EACvB,KAAK,eAAe,GACrB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,SAAS,EACT,OAAO,EACP,wBAAwB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,yBAAyB,EACzB,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,8BAA8B,EAC9B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,IAAI,EACJ,eAAe,EACf,YAAY,EACZ,UAAU,EACV,oBAAoB,EACpB,cAAc,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -396,7 +396,7 @@ class Router {
396
396
  }
397
397
  return;
398
398
  }
399
- async handle(context) {
399
+ async preHandle(context) {
400
400
  const method = context.method;
401
401
  const path = this.normalizePath(context.path);
402
402
  const route = this.findRoute(method, path);
@@ -413,6 +413,15 @@ class Router {
413
413
  method: route.methodName
414
414
  };
415
415
  }
416
+ }
417
+ async handle(context) {
418
+ await this.preHandle(context);
419
+ const method = context.method;
420
+ const path = this.normalizePath(context.path);
421
+ const route = this.findRoute(method, path);
422
+ if (!route) {
423
+ return;
424
+ }
416
425
  return await route.execute(context);
417
426
  }
418
427
  getRoutes() {
@@ -1920,6 +1929,7 @@ class Application {
1920
1929
  }
1921
1930
  const registry = RouteRegistry.getInstance();
1922
1931
  const router = registry.getRouter();
1932
+ await router.preHandle(context);
1923
1933
  return await this.middlewarePipeline.run(context, async () => {
1924
1934
  const response = await router.handle(context);
1925
1935
  if (response) {
@@ -2445,6 +2455,8 @@ SwaggerModule = __legacyDecorateClassTS([
2445
2455
  })
2446
2456
  ], SwaggerModule);
2447
2457
  // src/security/context.ts
2458
+ import { AsyncLocalStorage } from "async_hooks";
2459
+
2448
2460
  class SecurityContextImpl {
2449
2461
  _authentication = null;
2450
2462
  get authentication() {
@@ -2468,17 +2480,24 @@ class SecurityContextImpl {
2468
2480
  }
2469
2481
 
2470
2482
  class SecurityContextHolder {
2471
- static contexts = new Map;
2483
+ static storage = new AsyncLocalStorage;
2472
2484
  static getContext() {
2473
- const threadId = Bun.main ? 0 : Date.now();
2474
- if (!this.contexts.has(threadId)) {
2475
- this.contexts.set(threadId, new SecurityContextImpl);
2485
+ let context = this.storage.getStore();
2486
+ if (!context) {
2487
+ context = new SecurityContextImpl;
2488
+ this.storage.enterWith(context);
2476
2489
  }
2477
- return this.contexts.get(threadId);
2490
+ return context;
2491
+ }
2492
+ static runWithContext(callback) {
2493
+ const existing = this.storage.getStore() ?? new SecurityContextImpl;
2494
+ return this.storage.run(existing, callback);
2478
2495
  }
2479
2496
  static clearContext() {
2480
- const threadId = Bun.main ? 0 : Date.now();
2481
- this.contexts.delete(threadId);
2497
+ const context = this.storage.getStore();
2498
+ if (context) {
2499
+ context.clear();
2500
+ }
2482
2501
  }
2483
2502
  }
2484
2503
  // src/security/authentication-manager.ts
@@ -2532,7 +2551,10 @@ function getAuthMetadata(target, propertyKey) {
2532
2551
  }
2533
2552
  function requiresAuth(target, propertyKey) {
2534
2553
  const config = getAuthMetadata(target, propertyKey);
2535
- return config?.required !== false;
2554
+ if (!config) {
2555
+ return false;
2556
+ }
2557
+ return config.required !== false;
2536
2558
  }
2537
2559
  function checkRoles(target, propertyKey, userRoles = []) {
2538
2560
  const config = getAuthMetadata(target, propertyKey);
@@ -2552,53 +2574,58 @@ function createSecurityFilter(config) {
2552
2574
  extractToken
2553
2575
  } = config;
2554
2576
  return async (ctx, next) => {
2555
- const path = ctx.request.url.split("?")[0];
2556
- if (excludePaths.some((exclude) => path.startsWith(exclude))) {
2557
- return await next();
2558
- }
2559
- const securityContext = SecurityContextHolder.getContext();
2560
- try {
2561
- const token = extractToken ? extractToken(ctx) : extractTokenFromHeader(ctx);
2562
- if (token) {
2563
- const request = {
2564
- principal: "",
2565
- credentials: token,
2566
- type: "jwt"
2567
- };
2568
- const authentication = await authenticationManager.authenticate(request);
2569
- if (authentication) {
2570
- securityContext.setAuthentication(authentication);
2571
- }
2577
+ return SecurityContextHolder.runWithContext(async () => {
2578
+ const path = ctx.path || ctx.request.url.split("?")[0].replace(/^https?:\/\/[^/]+/, "");
2579
+ if (excludePaths.some((exclude) => path.startsWith(exclude))) {
2580
+ return await next();
2572
2581
  }
2573
- const handler = ctx.routeHandler;
2574
- if (handler) {
2575
- const controller = handler.controller;
2576
- const method = handler.method;
2577
- if (requiresAuth(controller, method)) {
2578
- const authentication = securityContext.authentication;
2579
- if (!authentication || !authentication.authenticated) {
2580
- throw new UnauthorizedException("Authentication required");
2582
+ const securityContext = SecurityContextHolder.getContext();
2583
+ try {
2584
+ const token = extractToken ? extractToken(ctx) : extractTokenFromHeader(ctx);
2585
+ if (token) {
2586
+ const request = {
2587
+ principal: "",
2588
+ credentials: token,
2589
+ type: "jwt"
2590
+ };
2591
+ const authentication = await authenticationManager.authenticate(request);
2592
+ if (authentication) {
2593
+ securityContext.setAuthentication(authentication);
2581
2594
  }
2582
- const requiredRoles = getRequiredRoles(controller, method);
2583
- if (requiredRoles.length > 0) {
2584
- const hasAccess = accessDecisionManager.decide(authentication, requiredRoles);
2585
- if (!hasAccess) {
2586
- const userRoles = authentication.authorities || [];
2587
- throw new ForbiddenException(`Insufficient permissions. Required roles: ${requiredRoles.join(", ")}, User roles: ${userRoles.join(", ")}`);
2595
+ }
2596
+ const handler = ctx.routeHandler;
2597
+ if (handler) {
2598
+ const controllerClass = handler.controller;
2599
+ const controllerTarget = controllerClass && controllerClass.prototype || controllerClass;
2600
+ const method = handler.method;
2601
+ if (requiresAuth(controllerTarget, method)) {
2602
+ const authentication = securityContext.authentication;
2603
+ if (!authentication || !authentication.authenticated) {
2604
+ throw new UnauthorizedException("Authentication required");
2605
+ }
2606
+ const requiredRoles = getRequiredRoles(controllerTarget, method);
2607
+ if (requiredRoles.length > 0) {
2608
+ const hasAccess = accessDecisionManager.decide(authentication, requiredRoles);
2609
+ if (!hasAccess) {
2610
+ const userRoles = authentication.authorities || [];
2611
+ throw new ForbiddenException(`Insufficient permissions. Required roles: ${requiredRoles.join(", ")}, User roles: ${userRoles.join(", ")}`);
2612
+ }
2588
2613
  }
2589
2614
  }
2615
+ } else if (defaultAuthRequired && !securityContext.isAuthenticated()) {
2616
+ throw new UnauthorizedException("Authentication required");
2590
2617
  }
2591
- } else if (defaultAuthRequired && !securityContext.isAuthenticated()) {
2592
- throw new UnauthorizedException("Authentication required");
2618
+ ctx.security = securityContext;
2619
+ ctx.auth = {
2620
+ isAuthenticated: securityContext.isAuthenticated(),
2621
+ user: securityContext.getPrincipal(),
2622
+ payload: securityContext.authentication?.details
2623
+ };
2624
+ return await next();
2625
+ } finally {
2626
+ SecurityContextHolder.clearContext();
2593
2627
  }
2594
- ctx.security = securityContext;
2595
- ctx.auth = {
2596
- isAuthenticated: securityContext.isAuthenticated(),
2597
- user: securityContext.getPrincipal(),
2598
- payload: securityContext.authentication?.details
2599
- };
2600
- return await next();
2601
- } finally {}
2628
+ });
2602
2629
  };
2603
2630
  }
2604
2631
  function extractTokenFromHeader(ctx) {
@@ -3111,6 +3138,206 @@ SecurityModule = __legacyDecorateClassTS([
3111
3138
  middlewares: []
3112
3139
  })
3113
3140
  ], SecurityModule);
3141
+ // src/config/service.ts
3142
+ class ConfigService {
3143
+ config;
3144
+ namespace;
3145
+ constructor(config, namespace) {
3146
+ this.config = config;
3147
+ this.namespace = namespace;
3148
+ }
3149
+ getAll() {
3150
+ return this.config;
3151
+ }
3152
+ get(key, defaultValue) {
3153
+ const namespacedKey = this.applyNamespace(key);
3154
+ const value = this.getValueByPath(this.config, namespacedKey);
3155
+ if (value === undefined) {
3156
+ return defaultValue;
3157
+ }
3158
+ return value;
3159
+ }
3160
+ getRequired(key) {
3161
+ const value = this.get(key);
3162
+ if (value === undefined) {
3163
+ throw new Error(`Config value required for key: ${key}`);
3164
+ }
3165
+ return value;
3166
+ }
3167
+ withNamespace(namespace) {
3168
+ return new ConfigService(this.config, namespace);
3169
+ }
3170
+ applyNamespace(key) {
3171
+ if (!this.namespace) {
3172
+ return key;
3173
+ }
3174
+ if (!key) {
3175
+ return this.namespace;
3176
+ }
3177
+ if (key.startsWith(this.namespace + ".")) {
3178
+ return key;
3179
+ }
3180
+ return `${this.namespace}.${key}`;
3181
+ }
3182
+ getValueByPath(obj, path) {
3183
+ if (!path) {
3184
+ return obj;
3185
+ }
3186
+ const segments = path.split(".");
3187
+ let current = obj;
3188
+ for (const segment of segments) {
3189
+ if (current === undefined || current === null || typeof current !== "object") {
3190
+ return;
3191
+ }
3192
+ current = current[segment];
3193
+ }
3194
+ return current;
3195
+ }
3196
+ }
3197
+
3198
+ // src/config/types.ts
3199
+ var CONFIG_SERVICE_TOKEN = Symbol("@dangao/bun-server:config:service");
3200
+
3201
+ // src/config/config-module.ts
3202
+ class ConfigModule {
3203
+ static forRoot(options = {}) {
3204
+ const providers2 = [];
3205
+ const env = ConfigModule.snapshotEnv();
3206
+ const defaultConfig = options.defaultConfig ?? {};
3207
+ const loadedConfig = options.load ? options.load(env) : {};
3208
+ const mergedConfig = {
3209
+ ...defaultConfig,
3210
+ ...loadedConfig
3211
+ };
3212
+ const service = new ConfigService(mergedConfig, options.namespace);
3213
+ if (options.validate) {
3214
+ options.validate(mergedConfig);
3215
+ }
3216
+ providers2.push({
3217
+ provide: CONFIG_SERVICE_TOKEN,
3218
+ useValue: service
3219
+ }, ConfigService);
3220
+ const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, ConfigModule) || {};
3221
+ const metadata = {
3222
+ ...existingMetadata,
3223
+ providers: [...existingMetadata.providers || [], ...providers2],
3224
+ exports: [
3225
+ ...existingMetadata.exports || [],
3226
+ CONFIG_SERVICE_TOKEN,
3227
+ ConfigService
3228
+ ]
3229
+ };
3230
+ Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, ConfigModule);
3231
+ return ConfigModule;
3232
+ }
3233
+ static snapshotEnv() {
3234
+ const env = {};
3235
+ for (const [key, value] of Object.entries(process.env)) {
3236
+ env[key] = value;
3237
+ }
3238
+ return env;
3239
+ }
3240
+ }
3241
+ ConfigModule = __legacyDecorateClassTS([
3242
+ Module({
3243
+ providers: []
3244
+ })
3245
+ ], ConfigModule);
3246
+ // src/health/types.ts
3247
+ var HEALTH_INDICATORS_TOKEN = Symbol("@dangao/bun-server:health:indicators");
3248
+ var HEALTH_OPTIONS_TOKEN = Symbol("@dangao/bun-server:health:options");
3249
+
3250
+ // src/health/controller.ts
3251
+ class HealthController {
3252
+ indicators;
3253
+ options;
3254
+ constructor(indicators = [], options) {
3255
+ this.indicators = indicators;
3256
+ this.options = options;
3257
+ }
3258
+ async health() {
3259
+ return await this.checkIndicators();
3260
+ }
3261
+ async ready() {
3262
+ return await this.checkIndicators();
3263
+ }
3264
+ async checkIndicators() {
3265
+ const details = {};
3266
+ for (const indicator of this.indicators || []) {
3267
+ try {
3268
+ const result = await indicator.check();
3269
+ details[indicator.name] = result;
3270
+ } catch (error) {
3271
+ details[indicator.name] = {
3272
+ status: "down",
3273
+ details: {
3274
+ error: error.message
3275
+ }
3276
+ };
3277
+ }
3278
+ }
3279
+ const allUp = Object.keys(details).length === 0 || Object.values(details).every((result) => result.status === "up");
3280
+ return {
3281
+ status: allUp ? "up" : "down",
3282
+ details
3283
+ };
3284
+ }
3285
+ }
3286
+ __legacyDecorateClassTS([
3287
+ GET("/health"),
3288
+ __legacyMetadataTS("design:type", Function),
3289
+ __legacyMetadataTS("design:paramtypes", []),
3290
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
3291
+ ], HealthController.prototype, "health", null);
3292
+ __legacyDecorateClassTS([
3293
+ GET("/ready"),
3294
+ __legacyMetadataTS("design:type", Function),
3295
+ __legacyMetadataTS("design:paramtypes", []),
3296
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
3297
+ ], HealthController.prototype, "ready", null);
3298
+ HealthController = __legacyDecorateClassTS([
3299
+ Controller("/"),
3300
+ __legacyDecorateParamTS(0, Inject(HEALTH_INDICATORS_TOKEN)),
3301
+ __legacyDecorateParamTS(1, Inject(HEALTH_OPTIONS_TOKEN)),
3302
+ __legacyMetadataTS("design:paramtypes", [
3303
+ Array,
3304
+ typeof HealthModuleOptions === "undefined" ? Object : HealthModuleOptions
3305
+ ])
3306
+ ], HealthController);
3307
+
3308
+ // src/health/health-module.ts
3309
+ class HealthModule {
3310
+ static forRoot(options = {}) {
3311
+ const providers2 = [];
3312
+ const indicators = options.indicators ?? [];
3313
+ providers2.push({
3314
+ provide: HEALTH_INDICATORS_TOKEN,
3315
+ useValue: indicators
3316
+ }, {
3317
+ provide: HEALTH_OPTIONS_TOKEN,
3318
+ useValue: options
3319
+ });
3320
+ const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, HealthModule) || {};
3321
+ const metadata = {
3322
+ ...existingMetadata,
3323
+ controllers: [...existingMetadata.controllers || [], HealthController],
3324
+ providers: [...existingMetadata.providers || [], ...providers2],
3325
+ exports: [
3326
+ ...existingMetadata.exports || [],
3327
+ HEALTH_INDICATORS_TOKEN,
3328
+ HEALTH_OPTIONS_TOKEN
3329
+ ]
3330
+ };
3331
+ Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, HealthModule);
3332
+ return HealthModule;
3333
+ }
3334
+ }
3335
+ HealthModule = __legacyDecorateClassTS([
3336
+ Module({
3337
+ controllers: [HealthController],
3338
+ providers: []
3339
+ })
3340
+ ], HealthModule);
3114
3341
  // src/testing/harness.ts
3115
3342
  import { performance as performance2 } from "perf_hooks";
3116
3343
 
@@ -3236,7 +3463,10 @@ export {
3236
3463
  Injectable,
3237
3464
  Inject,
3238
3465
  HttpException,
3466
+ HealthModule,
3239
3467
  Header,
3468
+ HEALTH_OPTIONS_TOKEN,
3469
+ HEALTH_INDICATORS_TOKEN,
3240
3470
  GET,
3241
3471
  ForbiddenException,
3242
3472
  ExceptionFilterRegistry,
@@ -3245,6 +3475,9 @@ export {
3245
3475
  Controller,
3246
3476
  Context,
3247
3477
  Container,
3478
+ ConfigService,
3479
+ ConfigModule,
3480
+ CONFIG_SERVICE_TOKEN,
3248
3481
  BunServer,
3249
3482
  BodyParser,
3250
3483
  Body,
@@ -65,7 +65,12 @@ export declare class Router {
65
65
  */
66
66
  findRoute(method: HttpMethod, path: string): Route | undefined;
67
67
  /**
68
- * 处理请求
68
+ * 预处理请求:仅匹配路由并设置路径参数 / routeHandler,但不执行处理器
69
+ * 供安全过滤器等中间件在真正执行前基于路由元数据做鉴权
70
+ */
71
+ preHandle(context: Context): Promise<void>;
72
+ /**
73
+ * 处理请求(包含路由匹配 + 执行)
69
74
  * @param context - 请求上下文
70
75
  * @returns 响应对象,如果没有匹配的路由则返回 undefined
71
76
  */
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,qBAAa,MAAM;IACjB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;OAQG;IACI,QAAQ,CACb,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,WAAW,GAAE,UAAU,EAAO,EAC9B,eAAe,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACrD,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI;IAaP;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAItF;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIxF;;;;OAIG;IACI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIvF;;;;;OAKG;IACI,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAerE;;;;OAIG;IACU,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IA4BpE;;;OAGG;IACI,SAAS,IAAI,SAAS,KAAK,EAAE;IAIpC;;OAEG;IACI,KAAK,IAAI,IAAI;CAKrB"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,qBAAa,MAAM;IACjB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;OAQG;IACI,QAAQ,CACb,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,WAAW,GAAE,UAAU,EAAO,EAC9B,eAAe,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACrD,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI;IAaP;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAItF;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIxF;;;;OAIG;IACI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIvF;;;;;OAKG;IACI,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAerE;;;OAGG;IACU,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBvD;;;;OAIG;IACU,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAepE;;;OAGG;IACI,SAAS,IAAI,SAAS,KAAK,EAAE;IAIpC;;OAEG;IACI,KAAK,IAAI,IAAI;CAKrB"}
@@ -33,13 +33,18 @@ export declare class SecurityContextImpl implements SecurityContext {
33
33
  * 安全上下文持有者(ThreadLocal 模式)
34
34
  */
35
35
  export declare class SecurityContextHolder {
36
- private static readonly contexts;
36
+ private static readonly storage;
37
37
  /**
38
38
  * 获取当前上下文
39
39
  */
40
40
  static getContext(): SecurityContextImpl;
41
41
  /**
42
- * 清除上下文
42
+ * 在给定回调中运行,绑定独立的安全上下文(每个请求一个)
43
+ * @param callback - 要在安全上下文中执行的回调
44
+ */
45
+ static runWithContext<T>(callback: () => T): T;
46
+ /**
47
+ * 清除当前上下文中的认证信息
43
48
  */
44
49
  static clearContext(): void;
45
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/security/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1E;;GAEG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,eAAe,CAA+B;IAEtD;;OAEG;IACH,IAAW,cAAc,IAAI,cAAc,GAAG,IAAI,CAEjD;IAED;;OAEG;IACI,iBAAiB,CAAC,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI;IAIrE;;OAEG;IACI,eAAe,IAAI,OAAO;IAIjC;;OAEG;IACI,YAAY,IAAI,SAAS,GAAG,IAAI;IAIvC;;OAEG;IACI,cAAc,IAAI,MAAM,EAAE;IAIjC;;OAEG;IACI,KAAK,IAAI,IAAI;CAGrB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAA0C;IAE1E;;OAEG;WACW,UAAU,IAAI,mBAAmB;IAQ/C;;OAEG;WACW,YAAY,IAAI,IAAI;CAInC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/security/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1E;;GAEG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,eAAe,CAA+B;IAEtD;;OAEG;IACH,IAAW,cAAc,IAAI,cAAc,GAAG,IAAI,CAEjD;IAED;;OAEG;IACI,iBAAiB,CAAC,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI;IAIrE;;OAEG;IACI,eAAe,IAAI,OAAO;IAIjC;;OAEG;IACI,YAAY,IAAI,SAAS,GAAG,IAAI;IAIvC;;OAEG;IACI,cAAc,IAAI,MAAM,EAAE;IAIjC;;OAEG;IACI,KAAK,IAAI,IAAI;CAGrB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAgD;IAE/E;;OAEG;WACW,UAAU,IAAI,mBAAmB;IAS/C;;;OAGG;WACW,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC;IAKrD;;OAEG;WACW,YAAY,IAAI,IAAI;CAMnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/security/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,SAAS,CAAC;AAIrE;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D;;OAEG;IACH,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C;;OAEG;IACH,qBAAqB,CAAC,EAAE,8BAA8B,CAAC;IACvD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;CAChD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,UAAU,CAqF7E"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/security/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,SAAS,CAAC;AAIrE;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D;;OAEG;IACH,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C;;OAEG;IACH,qBAAqB,CAAC,EAAE,8BAA8B,CAAC;IACvD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;CAChD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,UAAU,CA2F7E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangao/bun-server",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/readme.md CHANGED
@@ -31,7 +31,7 @@
31
31
  可扩展**:松耦合的模块系统、扩展系统与日志框架,既可以快速起步,也能按需裁剪。
32
32
  - **Monorepo 友好**:原生支持 Bun workspaces,使用 `workspace:*`
33
33
  协议管理内部依赖,配合 catalog 统一版本,完美适配多包协作场景。
34
- - **完整测试矩阵**:内置单元/集成测试、压力与基准测试用例,便于持续优化。
34
+ - **完整测试矩阵**:内置单元/集成测试、压力与基准测试用例,Security 和 Swagger 模块测试覆盖完整,便于持续优化。
35
35
 
36
36
  ## 核心特性
37
37
 
@@ -43,6 +43,8 @@
43
43
  **中间件管道**:支持全局/控制器/方法级中间件,内置日志、错误处理、CORS、文件上传、静态资源等。
44
44
  - ✅ **输入校验**:声明式验证装饰器,直连 `ValidationError` 与异常过滤器。
45
45
  - 📡 **WebSocket**:`@WebSocketGateway`、`@OnMessage` 等装饰器级开发体验。
46
+ - 📖 **Swagger/OpenAPI**:内置 Swagger 插件,支持 `@ApiTags`、`@ApiOperation`、`@ApiParam`、`@ApiBody`、`@ApiResponse` 等装饰器,自动生成 API 文档和 Swagger UI。
47
+ - 🔐 **安全认证**:内置 SecurityModule,支持 JWT 和 OAuth2 认证,提供 `@Auth()` 装饰器进行角色权限控制。
46
48
  - 📚 **示例与文档**:多语言文档、基础/完整示例、基准脚本与最佳实践。
47
49
 
48
50
  ## 架构总览
@@ -126,11 +128,12 @@ bun --cwd=benchmark run bench:di # 仅运行 DI 基准
126
128
 
127
129
  ## 示例与扩展
128
130
 
129
- - `examples/basic-app.ts`:最小可运行示例,覆盖 DI + Logger + Middleware。
130
- - `examples/full-app.ts`:包含验证、文件上传、WebSocket、复杂控制器。
131
- - `examples/multi-module-app.ts`:多模块示例,展示模块间的依赖关系和服务共享。
132
- - `packages/@dangao/bun-server/src/extensions/`:官方扩展(如
133
- LoggerExtension),可用于注册第三方能力。
131
+ - `examples/basic-app.ts`:最小可运行示例,覆盖 DI + Logger + Middleware + Swagger + ConfigModule
132
+ - `examples/full-app.ts`:包含验证、文件上传、WebSocket、复杂控制器,使用 ConfigModule 管理端口与中间件配置。
133
+ - `examples/multi-module-app.ts`:多模块示例,展示模块间的依赖关系和服务共享,使用 ConfigModule 统一管理应用配置。
134
+ - `examples/auth-app.ts`:完整的认证演示,包含 JWT + OAuth2 认证流程、前端演示页面,并通过 ConfigModule 管理应用标题和端口。
135
+ - `packages/bun-server/src/extensions/`:官方扩展(如
136
+ LoggerExtension、SwaggerExtension),可用于注册第三方能力。
134
137
 
135
138
  ## 性能与 Benchmark
136
139
 
@@ -153,10 +156,11 @@ bun benchmark/di.bench.ts
153
156
  ## 文档与多语言支持
154
157
 
155
158
  - 中文默认文档位于 `docs/`
156
- - `docs/api.md`
157
- - `docs/guide.md`
158
- - `docs/best-practices.md`
159
- - `docs/migration.md`
159
+ - `docs/api.md` - API 参考文档
160
+ - `docs/guide.md` - 使用指南
161
+ - `docs/extensions.md` - 扩展系统说明(中间件、扩展、模块等)
162
+ - `docs/best-practices.md` - 最佳实践
163
+ - `docs/migration.md` - 迁移指南
160
164
  - 英文草稿位于
161
165
  `docs/en/`,与中文文件结构一致;如果缺失内容,请优先参考中文版本。
162
166