@dangao/bun-server 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/package.json +4 -2
  2. package/readme.md +163 -2
  3. package/src/auth/controller.ts +148 -0
  4. package/src/auth/decorators.ts +81 -0
  5. package/src/auth/index.ts +12 -0
  6. package/src/auth/jwt.ts +169 -0
  7. package/src/auth/oauth2.ts +244 -0
  8. package/src/auth/types.ts +248 -0
  9. package/src/cache/cache-module.ts +67 -0
  10. package/src/cache/decorators.ts +202 -0
  11. package/src/cache/index.ts +27 -0
  12. package/src/cache/service.ts +151 -0
  13. package/src/cache/types.ts +420 -0
  14. package/src/config/config-module.ts +76 -0
  15. package/src/config/index.ts +8 -0
  16. package/src/config/service.ts +93 -0
  17. package/src/config/types.ts +27 -0
  18. package/src/controller/controller.ts +251 -0
  19. package/src/controller/decorators.ts +84 -0
  20. package/src/controller/index.ts +7 -0
  21. package/src/controller/metadata.ts +27 -0
  22. package/src/controller/param-binder.ts +157 -0
  23. package/src/core/application.ts +233 -0
  24. package/src/core/context.ts +228 -0
  25. package/src/core/index.ts +4 -0
  26. package/src/core/server.ts +128 -0
  27. package/src/core/types.ts +2 -0
  28. package/src/database/connection-manager.ts +239 -0
  29. package/src/database/connection-pool.ts +322 -0
  30. package/src/database/database-extension.ts +62 -0
  31. package/src/database/database-module.ts +115 -0
  32. package/src/database/health-indicator.ts +51 -0
  33. package/src/database/index.ts +47 -0
  34. package/src/database/orm/decorators.ts +155 -0
  35. package/src/database/orm/drizzle-repository.ts +39 -0
  36. package/src/database/orm/index.ts +23 -0
  37. package/src/database/orm/repository-decorator.ts +39 -0
  38. package/src/database/orm/repository.ts +103 -0
  39. package/src/database/orm/service.ts +49 -0
  40. package/src/database/orm/transaction-decorator.ts +45 -0
  41. package/src/database/orm/transaction-interceptor.ts +243 -0
  42. package/src/database/orm/transaction-manager.ts +276 -0
  43. package/src/database/orm/transaction-types.ts +140 -0
  44. package/src/database/orm/types.ts +99 -0
  45. package/src/database/service.ts +221 -0
  46. package/src/database/types.ts +171 -0
  47. package/src/di/container.ts +398 -0
  48. package/src/di/decorators.ts +228 -0
  49. package/src/di/index.ts +4 -0
  50. package/src/di/module-registry.ts +188 -0
  51. package/src/di/module.ts +65 -0
  52. package/src/di/types.ts +67 -0
  53. package/src/error/error-codes.ts +222 -0
  54. package/src/error/filter.ts +43 -0
  55. package/src/error/handler.ts +66 -0
  56. package/src/error/http-exception.ts +115 -0
  57. package/src/error/i18n.ts +217 -0
  58. package/src/error/index.ts +16 -0
  59. package/src/extensions/index.ts +5 -0
  60. package/src/extensions/logger-extension.ts +31 -0
  61. package/src/extensions/logger-module.ts +69 -0
  62. package/src/extensions/types.ts +14 -0
  63. package/src/files/index.ts +5 -0
  64. package/src/files/static-middleware.ts +53 -0
  65. package/src/files/storage.ts +67 -0
  66. package/src/files/types.ts +33 -0
  67. package/src/files/upload-middleware.ts +45 -0
  68. package/src/health/controller.ts +76 -0
  69. package/src/health/health-module.ts +51 -0
  70. package/src/health/index.ts +12 -0
  71. package/src/health/types.ts +28 -0
  72. package/src/index.ts +270 -0
  73. package/src/metrics/collector.ts +209 -0
  74. package/src/metrics/controller.ts +40 -0
  75. package/src/metrics/index.ts +15 -0
  76. package/src/metrics/metrics-module.ts +58 -0
  77. package/src/metrics/middleware.ts +46 -0
  78. package/src/metrics/prometheus.ts +79 -0
  79. package/src/metrics/types.ts +103 -0
  80. package/src/middleware/builtin/cors.ts +60 -0
  81. package/src/middleware/builtin/error-handler.ts +90 -0
  82. package/src/middleware/builtin/file-upload.ts +42 -0
  83. package/src/middleware/builtin/index.ts +14 -0
  84. package/src/middleware/builtin/logger.ts +91 -0
  85. package/src/middleware/builtin/rate-limit.ts +252 -0
  86. package/src/middleware/builtin/static-file.ts +88 -0
  87. package/src/middleware/decorators.ts +91 -0
  88. package/src/middleware/index.ts +11 -0
  89. package/src/middleware/middleware.ts +13 -0
  90. package/src/middleware/pipeline.ts +93 -0
  91. package/src/queue/decorators.ts +110 -0
  92. package/src/queue/index.ts +26 -0
  93. package/src/queue/queue-module.ts +64 -0
  94. package/src/queue/service.ts +302 -0
  95. package/src/queue/types.ts +341 -0
  96. package/src/request/body-parser.ts +133 -0
  97. package/src/request/file-handler.ts +46 -0
  98. package/src/request/index.ts +5 -0
  99. package/src/request/request.ts +107 -0
  100. package/src/request/response.ts +150 -0
  101. package/src/router/decorators.ts +122 -0
  102. package/src/router/index.ts +6 -0
  103. package/src/router/registry.ts +98 -0
  104. package/src/router/route.ts +140 -0
  105. package/src/router/router.ts +241 -0
  106. package/src/router/types.ts +27 -0
  107. package/src/security/access-decision-manager.ts +34 -0
  108. package/src/security/authentication-manager.ts +47 -0
  109. package/src/security/context.ts +92 -0
  110. package/src/security/filter.ts +162 -0
  111. package/src/security/index.ts +8 -0
  112. package/src/security/providers/index.ts +3 -0
  113. package/src/security/providers/jwt-provider.ts +60 -0
  114. package/src/security/providers/oauth2-provider.ts +70 -0
  115. package/src/security/security-module.ts +145 -0
  116. package/src/security/types.ts +165 -0
  117. package/src/session/decorators.ts +45 -0
  118. package/src/session/index.ts +19 -0
  119. package/src/session/middleware.ts +143 -0
  120. package/src/session/service.ts +218 -0
  121. package/src/session/session-module.ts +69 -0
  122. package/src/session/types.ts +373 -0
  123. package/src/swagger/decorators.ts +133 -0
  124. package/src/swagger/generator.ts +234 -0
  125. package/src/swagger/index.ts +7 -0
  126. package/src/swagger/swagger-extension.ts +41 -0
  127. package/src/swagger/swagger-module.ts +83 -0
  128. package/src/swagger/types.ts +188 -0
  129. package/src/swagger/ui.ts +98 -0
  130. package/src/testing/harness.ts +96 -0
  131. package/src/validation/decorators.ts +95 -0
  132. package/src/validation/errors.ts +28 -0
  133. package/src/validation/index.ts +14 -0
  134. package/src/validation/types.ts +35 -0
  135. package/src/validation/validator.ts +63 -0
  136. package/src/websocket/decorators.ts +51 -0
  137. package/src/websocket/index.ts +12 -0
  138. package/src/websocket/registry.ts +133 -0
  139. package/tests/cache/cache-module.test.ts +212 -0
  140. package/tests/config/config-module.test.ts +151 -0
  141. package/tests/controller/controller.test.ts +189 -0
  142. package/tests/core/application.test.ts +57 -0
  143. package/tests/core/context-body.test.ts +44 -0
  144. package/tests/core/context.test.ts +86 -0
  145. package/tests/core/edge-cases.test.ts +432 -0
  146. package/tests/database/database-module.test.ts +385 -0
  147. package/tests/database/orm.test.ts +164 -0
  148. package/tests/database/postgres-mysql-integration.test.ts +395 -0
  149. package/tests/database/transaction.test.ts +238 -0
  150. package/tests/di/container.test.ts +264 -0
  151. package/tests/di/module.test.ts +128 -0
  152. package/tests/error/error-codes.test.ts +121 -0
  153. package/tests/error/error-handler.test.ts +68 -0
  154. package/tests/error/error-handling.test.ts +254 -0
  155. package/tests/error/http-exception.test.ts +37 -0
  156. package/tests/error/i18n-integration.test.ts +175 -0
  157. package/tests/extensions/logger-extension.test.ts +40 -0
  158. package/tests/files/static-middleware.test.ts +67 -0
  159. package/tests/files/upload-middleware.test.ts +43 -0
  160. package/tests/health/health-module.test.ts +116 -0
  161. package/tests/integration/application-router.test.ts +85 -0
  162. package/tests/integration/body-parsing.test.ts +88 -0
  163. package/tests/integration/cache-e2e.test.ts +114 -0
  164. package/tests/integration/oauth2-e2e.test.ts +615 -0
  165. package/tests/integration/session-e2e.test.ts +207 -0
  166. package/tests/metrics/metrics-module.test.ts +178 -0
  167. package/tests/middleware/builtin.test.ts +206 -0
  168. package/tests/middleware/file-upload.test.ts +41 -0
  169. package/tests/middleware/middleware.test.ts +120 -0
  170. package/tests/middleware/pipeline.test.ts +72 -0
  171. package/tests/middleware/rate-limit.test.ts +314 -0
  172. package/tests/middleware/static-file.test.ts +62 -0
  173. package/tests/perf/harness.test.ts +48 -0
  174. package/tests/perf/optimization.test.ts +183 -0
  175. package/tests/perf/regression.test.ts +120 -0
  176. package/tests/queue/queue-module.test.ts +217 -0
  177. package/tests/request/body-parser.test.ts +96 -0
  178. package/tests/request/response.test.ts +99 -0
  179. package/tests/router/decorators.test.ts +48 -0
  180. package/tests/router/registry.test.ts +51 -0
  181. package/tests/router/route.test.ts +71 -0
  182. package/tests/router/router-normalization.test.ts +106 -0
  183. package/tests/router/router.test.ts +133 -0
  184. package/tests/security/access-decision-manager.test.ts +84 -0
  185. package/tests/security/authentication-manager.test.ts +81 -0
  186. package/tests/security/context.test.ts +302 -0
  187. package/tests/security/filter.test.ts +225 -0
  188. package/tests/security/jwt-provider.test.ts +106 -0
  189. package/tests/security/oauth2-provider.test.ts +269 -0
  190. package/tests/security/security-module.test.ts +143 -0
  191. package/tests/session/session-module.test.ts +307 -0
  192. package/tests/stress/di-stress.test.ts +30 -0
  193. package/tests/swagger/decorators.test.ts +153 -0
  194. package/tests/swagger/generator.test.ts +202 -0
  195. package/tests/swagger/swagger-extension.test.ts +72 -0
  196. package/tests/swagger/swagger-module.test.ts +79 -0
  197. package/tests/utils/test-port.ts +10 -0
  198. package/tests/validation/controller-validation.test.ts +64 -0
  199. package/tests/validation/validation.test.ts +42 -0
  200. package/tests/websocket/gateway.test.ts +68 -0
@@ -0,0 +1,76 @@
1
+ import { Controller } from '../controller';
2
+ import { GET } from '../router/decorators';
3
+ import { Inject } from '../di/decorators';
4
+
5
+ import type {
6
+ HealthIndicator,
7
+ HealthIndicatorResult,
8
+ HealthStatus,
9
+ } from './types';
10
+ import type { HealthModuleOptions } from './types';
11
+ import { HEALTH_INDICATORS_TOKEN, HEALTH_OPTIONS_TOKEN } from './types';
12
+
13
+ /**
14
+ * 健康检查控制器
15
+ *
16
+ * 提供 `/health` 和 `/ready` 两个端点:
17
+ * - /health:存活检查(liveness)
18
+ * - /ready:就绪检查(readiness)
19
+ */
20
+ @Controller('/')
21
+ export class HealthController {
22
+ public constructor(
23
+ @Inject(HEALTH_INDICATORS_TOKEN)
24
+ private readonly indicators: HealthIndicator[] = [],
25
+ @Inject(HEALTH_OPTIONS_TOKEN)
26
+ private readonly options?: HealthModuleOptions,
27
+ ) {}
28
+
29
+ /**
30
+ * 存活检查
31
+ */
32
+ @GET('/health')
33
+ public async health(): Promise<HealthStatus> {
34
+ return await this.checkIndicators();
35
+ }
36
+
37
+ /**
38
+ * 就绪检查
39
+ */
40
+ @GET('/ready')
41
+ public async ready(): Promise<HealthStatus> {
42
+ return await this.checkIndicators();
43
+ }
44
+
45
+ /**
46
+ * 执行所有健康检查指示器
47
+ */
48
+ private async checkIndicators(): Promise<HealthStatus> {
49
+ const details: Record<string, HealthIndicatorResult> = {};
50
+
51
+ for (const indicator of this.indicators || []) {
52
+ try {
53
+ const result = await indicator.check();
54
+ details[indicator.name] = result;
55
+ } catch (error) {
56
+ details[indicator.name] = {
57
+ status: 'down',
58
+ details: {
59
+ error: (error as Error).message,
60
+ },
61
+ };
62
+ }
63
+ }
64
+
65
+ const allUp =
66
+ Object.keys(details).length === 0 ||
67
+ Object.values(details).every((result) => result.status === 'up');
68
+
69
+ return {
70
+ status: allUp ? 'up' : 'down',
71
+ details,
72
+ };
73
+ }
74
+ }
75
+
76
+
@@ -0,0 +1,51 @@
1
+ import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../di/module';
2
+
3
+ import { HealthController } from './controller';
4
+ import type { HealthIndicator, HealthModuleOptions } from './types';
5
+ import { HEALTH_INDICATORS_TOKEN, HEALTH_OPTIONS_TOKEN } from './types';
6
+
7
+ @Module({
8
+ controllers: [HealthController],
9
+ providers: [],
10
+ })
11
+ export class HealthModule {
12
+ /**
13
+ * 创建健康检查模块
14
+ * @param options - 模块配置
15
+ */
16
+ public static forRoot(options: HealthModuleOptions = {}): typeof HealthModule {
17
+ const providers: ModuleProvider[] = [];
18
+
19
+ const indicators: HealthIndicator[] = options.indicators ?? [];
20
+
21
+ providers.push(
22
+ {
23
+ provide: HEALTH_INDICATORS_TOKEN,
24
+ useValue: indicators,
25
+ },
26
+ {
27
+ provide: HEALTH_OPTIONS_TOKEN,
28
+ useValue: options,
29
+ },
30
+ );
31
+
32
+ // 动态更新模块元数据
33
+ const existingMetadata =
34
+ Reflect.getMetadata(MODULE_METADATA_KEY, HealthModule) || {};
35
+ const metadata = {
36
+ ...existingMetadata,
37
+ controllers: [...(existingMetadata.controllers || []), HealthController],
38
+ providers: [...(existingMetadata.providers || []), ...providers],
39
+ exports: [
40
+ ...(existingMetadata.exports || []),
41
+ HEALTH_INDICATORS_TOKEN,
42
+ HEALTH_OPTIONS_TOKEN,
43
+ ],
44
+ };
45
+ Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, HealthModule);
46
+
47
+ return HealthModule;
48
+ }
49
+ }
50
+
51
+
@@ -0,0 +1,12 @@
1
+ export { HealthModule } from './health-module';
2
+ export { HealthController } from './controller';
3
+ export {
4
+ HEALTH_INDICATORS_TOKEN,
5
+ HEALTH_OPTIONS_TOKEN,
6
+ type HealthIndicator,
7
+ type HealthIndicatorResult,
8
+ type HealthStatus,
9
+ type HealthModuleOptions,
10
+ } from './types';
11
+
12
+
@@ -0,0 +1,28 @@
1
+ export const HEALTH_INDICATORS_TOKEN = Symbol('@dangao/bun-server:health:indicators');
2
+ export const HEALTH_OPTIONS_TOKEN = Symbol('@dangao/bun-server:health:options');
3
+
4
+ export type HealthStatusValue = 'up' | 'down';
5
+
6
+ export interface HealthIndicatorResult {
7
+ status: HealthStatusValue;
8
+ details?: Record<string, unknown>;
9
+ }
10
+
11
+ export interface HealthIndicator {
12
+ name: string;
13
+ check(): Promise<HealthIndicatorResult> | HealthIndicatorResult;
14
+ }
15
+
16
+ export interface HealthStatus {
17
+ status: HealthStatusValue;
18
+ details: Record<string, HealthIndicatorResult>;
19
+ }
20
+
21
+ export interface HealthModuleOptions {
22
+ /**
23
+ * 健康检查指示器列表
24
+ */
25
+ indicators?: HealthIndicator[];
26
+ }
27
+
28
+
package/src/index.ts ADDED
@@ -0,0 +1,270 @@
1
+ export { Application, type ApplicationOptions } from './core/application';
2
+ export { BunServer, type ServerOptions } from './core/server';
3
+ export { Context } from './core/context';
4
+ export { Route, Router, RouteRegistry } from './router';
5
+ export { GET, POST, PUT, DELETE, PATCH } from './router/decorators';
6
+ export type { HttpMethod, RouteHandler, RouteMatch } from './router/types';
7
+ export { BodyParser, RequestWrapper, ResponseBuilder } from './request';
8
+ export { Body, Query, Param, Header, ParamBinder, Controller, ControllerRegistry } from './controller';
9
+ export type { ParamMetadata, ControllerMetadata } from './controller';
10
+ export { Container } from './di/container';
11
+ export { Injectable, Inject } from './di/decorators';
12
+ export { Lifecycle, type ProviderConfig, type DependencyMetadata } from './di/types';
13
+ export {
14
+ Module,
15
+ type ModuleMetadata,
16
+ type ModuleProvider,
17
+ type ModuleClass,
18
+ } from './di/module';
19
+ export { ModuleRegistry } from './di/module-registry';
20
+ export { UseMiddleware, RateLimit, MiddlewarePipeline } from './middleware';
21
+ export type { Middleware, NextFunction } from './middleware';
22
+ export {
23
+ createLoggerMiddleware,
24
+ createRequestLoggingMiddleware,
25
+ createErrorHandlingMiddleware,
26
+ createCorsMiddleware,
27
+ createFileUploadMiddleware,
28
+ createStaticFileMiddleware,
29
+ createRateLimitMiddleware,
30
+ createTokenKeyGenerator,
31
+ createUserKeyGenerator,
32
+ type RateLimitOptions,
33
+ type RateLimitStore,
34
+ } from './middleware/builtin';
35
+ export {
36
+ Validate,
37
+ IsString,
38
+ IsNumber,
39
+ IsEmail,
40
+ IsOptional,
41
+ MinLength,
42
+ ValidationError,
43
+ type ValidationIssue,
44
+ } from './validation';
45
+ export {
46
+ HttpException,
47
+ BadRequestException,
48
+ UnauthorizedException,
49
+ ForbiddenException,
50
+ NotFoundException,
51
+ InternalServerErrorException,
52
+ ExceptionFilterRegistry,
53
+ type ExceptionFilter,
54
+ } from './error';
55
+ export {
56
+ WebSocketGateway,
57
+ OnOpen,
58
+ OnMessage,
59
+ OnClose,
60
+ WebSocketGatewayRegistry,
61
+ type WebSocketConnectionData,
62
+ } from './websocket';
63
+ export {
64
+ LoggerExtension,
65
+ LoggerModule,
66
+ LogLevel,
67
+ LOGGER_TOKEN,
68
+ type Logger,
69
+ type LoggerOptions,
70
+ type LoggerModuleOptions,
71
+ type LogEntry,
72
+ } from './extensions';
73
+ export {
74
+ SwaggerExtension,
75
+ SwaggerModule,
76
+ SwaggerGenerator,
77
+ createSwaggerUIMiddleware,
78
+ ApiTags,
79
+ ApiOperation,
80
+ ApiParam,
81
+ ApiBody,
82
+ ApiResponse,
83
+ type SwaggerOptions,
84
+ type SwaggerModuleOptions,
85
+ type SwaggerDocument,
86
+ type ApiOperationMetadata,
87
+ type ApiParamMetadata,
88
+ type ApiBodyMetadata,
89
+ type ApiResponseMetadata,
90
+ } from './swagger';
91
+ // Security 模块(推荐使用)
92
+ export {
93
+ SecurityModule,
94
+ SecurityContextHolder,
95
+ AuthenticationManager,
96
+ RoleBasedAccessDecisionManager,
97
+ JwtAuthenticationProvider,
98
+ OAuth2AuthenticationProvider,
99
+ createSecurityFilter,
100
+ type SecurityModuleConfig,
101
+ type SecurityConfig,
102
+ type SecurityContext,
103
+ type Authentication,
104
+ type AuthenticationProvider,
105
+ type AuthenticationRequest,
106
+ type Principal,
107
+ type Credentials,
108
+ type AccessDecisionManager,
109
+ } from './security';
110
+ export {
111
+ ConfigModule,
112
+ ConfigService,
113
+ CONFIG_SERVICE_TOKEN,
114
+ type ConfigModuleOptions,
115
+ } from './config';
116
+ export {
117
+ HealthModule,
118
+ type HealthIndicator,
119
+ type HealthIndicatorResult,
120
+ type HealthStatus,
121
+ type HealthModuleOptions,
122
+ HEALTH_INDICATORS_TOKEN,
123
+ HEALTH_OPTIONS_TOKEN,
124
+ } from './health';
125
+ export {
126
+ MetricsModule,
127
+ MetricsCollector,
128
+ PrometheusFormatter,
129
+ createHttpMetricsMiddleware,
130
+ METRICS_SERVICE_TOKEN,
131
+ METRICS_OPTIONS_TOKEN,
132
+ type MetricsModuleOptions,
133
+ type MetricType,
134
+ type MetricLabels,
135
+ type MetricValue,
136
+ type MetricDataPoint,
137
+ type CustomMetric,
138
+ } from './metrics';
139
+ export {
140
+ DatabaseModule,
141
+ DatabaseService,
142
+ DatabaseConnectionManager,
143
+ ConnectionPool,
144
+ DatabaseHealthIndicator,
145
+ DatabaseExtension,
146
+ DATABASE_SERVICE_TOKEN,
147
+ DATABASE_OPTIONS_TOKEN,
148
+ type DatabaseModuleOptions,
149
+ type DatabaseConfig,
150
+ type DatabaseType,
151
+ type ConnectionInfo,
152
+ type ConnectionPoolOptions,
153
+ type SqliteConfig,
154
+ type PostgresConfig,
155
+ type MysqlConfig,
156
+ // ORM exports
157
+ Entity,
158
+ Column,
159
+ PrimaryKey,
160
+ Repository,
161
+ BaseRepository,
162
+ DrizzleBaseRepository,
163
+ OrmService,
164
+ ORM_SERVICE_TOKEN,
165
+ getEntityMetadata,
166
+ getColumnMetadata,
167
+ getRepositoryMetadata,
168
+ type OrmModuleOptions,
169
+ type BaseRepository as BaseRepositoryInterface,
170
+ type EntityMetadata,
171
+ type ColumnMetadata,
172
+ // Transaction exports
173
+ Transactional,
174
+ TransactionManager,
175
+ TransactionInterceptor,
176
+ Propagation,
177
+ IsolationLevel,
178
+ TransactionStatus,
179
+ TRANSACTION_SERVICE_TOKEN,
180
+ getTransactionMetadata,
181
+ type TransactionOptions,
182
+ type TransactionContext,
183
+ } from './database';
184
+ // Auth 模块(底层实现,供 Security 模块使用)
185
+ export {
186
+ JWTUtil,
187
+ OAuth2Service,
188
+ OAuth2Controller,
189
+ Auth,
190
+ getAuthMetadata,
191
+ requiresAuth,
192
+ checkRoles,
193
+ OAUTH2_SERVICE_TOKEN,
194
+ JWT_UTIL_TOKEN,
195
+ type JWTConfig,
196
+ type JWTPayload,
197
+ type OAuth2Client,
198
+ type OAuth2AuthorizationRequest,
199
+ type OAuth2TokenRequest,
200
+ type OAuth2TokenResponse,
201
+ type UserInfo,
202
+ type AuthContext,
203
+ type AuthConfig,
204
+ } from './auth';
205
+ export {
206
+ PerformanceHarness,
207
+ StressTester,
208
+ type BenchmarkResult,
209
+ type StressResult,
210
+ } from './testing/harness';
211
+ // Cache 模块
212
+ export {
213
+ CacheModule,
214
+ CacheService,
215
+ Cacheable,
216
+ CacheEvict,
217
+ CachePut,
218
+ MemoryCacheStore,
219
+ RedisCacheStore,
220
+ CACHE_SERVICE_TOKEN,
221
+ CACHE_OPTIONS_TOKEN,
222
+ } from './cache';
223
+ export type {
224
+ CacheModuleOptions,
225
+ CacheStore,
226
+ RedisCacheStoreOptions,
227
+ CacheableOptions,
228
+ CacheEvictOptions,
229
+ CachePutOptions,
230
+ } from './cache';
231
+ // Queue 模块
232
+ export {
233
+ QueueModule,
234
+ QueueService,
235
+ Queue,
236
+ Cron,
237
+ MemoryQueueStore,
238
+ QUEUE_SERVICE_TOKEN,
239
+ QUEUE_OPTIONS_TOKEN,
240
+ } from './queue';
241
+ export type {
242
+ QueueModuleOptions,
243
+ QueueStore,
244
+ Job,
245
+ JobData,
246
+ JobHandler,
247
+ JobOptions,
248
+ CronOptions,
249
+ QueueOptions,
250
+ CronDecoratorOptions,
251
+ } from './queue';
252
+ // Session 模块
253
+ export {
254
+ SessionModule,
255
+ SessionService,
256
+ createSessionMiddleware,
257
+ SessionDecorator as Session,
258
+ MemorySessionStore,
259
+ RedisSessionStore,
260
+ SESSION_SERVICE_TOKEN,
261
+ SESSION_OPTIONS_TOKEN,
262
+ } from './session';
263
+ export type {
264
+ SessionModuleOptions,
265
+ SessionStore,
266
+ Session as SessionType,
267
+ SessionData,
268
+ RedisSessionStoreOptions,
269
+ } from './session';
270
+
@@ -0,0 +1,209 @@
1
+ import type {
2
+ CustomMetric,
3
+ MetricDataPoint,
4
+ MetricLabels,
5
+ MetricType,
6
+ MetricValue,
7
+ } from './types';
8
+
9
+ /**
10
+ * 指标收集器
11
+ */
12
+ export class MetricsCollector {
13
+ private counters: Map<string, Map<string, number>> = new Map();
14
+ private gauges: Map<string, Map<string, number>> = new Map();
15
+ private histograms: Map<string, Map<string, number[]>> = new Map();
16
+ private customMetrics: CustomMetric[] = [];
17
+
18
+ /**
19
+ * 注册自定义指标
20
+ */
21
+ public registerCustomMetric(metric: CustomMetric): void {
22
+ this.customMetrics.push(metric);
23
+ }
24
+
25
+ /**
26
+ * 增加计数器
27
+ */
28
+ public incrementCounter(name: string, labels?: MetricLabels, value: number = 1): void {
29
+ const key = this.getKey(name, labels);
30
+ const counterMap = this.counters.get(name) || new Map();
31
+ const current = counterMap.get(key) || 0;
32
+ counterMap.set(key, current + value);
33
+ this.counters.set(name, counterMap);
34
+ }
35
+
36
+ /**
37
+ * 设置仪表值
38
+ */
39
+ public setGauge(name: string, labels: MetricLabels | undefined, value: number): void {
40
+ const key = this.getKey(name, labels);
41
+ const gaugeMap = this.gauges.get(name) || new Map();
42
+ gaugeMap.set(key, value);
43
+ this.gauges.set(name, gaugeMap);
44
+ }
45
+
46
+ /**
47
+ * 观察直方图值
48
+ */
49
+ public observeHistogram(name: string, labels: MetricLabels | undefined, value: number): void {
50
+ const key = this.getKey(name, labels);
51
+ const histogramMap = this.histograms.get(name) || new Map();
52
+ const values = histogramMap.get(key) || [];
53
+ values.push(value);
54
+ histogramMap.set(key, values);
55
+ this.histograms.set(name, histogramMap);
56
+ }
57
+
58
+ /**
59
+ * 获取所有指标数据点
60
+ */
61
+ public async getAllDataPoints(): Promise<MetricDataPoint[]> {
62
+ const dataPoints: MetricDataPoint[] = [];
63
+
64
+ // 收集计数器
65
+ for (const [name, counterMap] of this.counters.entries()) {
66
+ for (const [key, value] of counterMap.entries()) {
67
+ const labels = this.parseKey(key);
68
+ dataPoints.push({
69
+ name,
70
+ type: 'counter',
71
+ value,
72
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined,
73
+ });
74
+ }
75
+ }
76
+
77
+ // 收集仪表
78
+ for (const [name, gaugeMap] of this.gauges.entries()) {
79
+ for (const [key, value] of gaugeMap.entries()) {
80
+ const labels = this.parseKey(key);
81
+ dataPoints.push({
82
+ name,
83
+ type: 'gauge',
84
+ value,
85
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined,
86
+ });
87
+ }
88
+ }
89
+
90
+ // 收集直方图(计算统计信息)
91
+ for (const [name, histogramMap] of this.histograms.entries()) {
92
+ for (const [key, values] of histogramMap.entries()) {
93
+ const labels = this.parseKey(key);
94
+ const sum = values.reduce((a, b) => a + b, 0);
95
+ const count = values.length;
96
+ const buckets = this.calculateBuckets(values);
97
+
98
+ // 添加 sum
99
+ dataPoints.push({
100
+ name: `${name}_sum`,
101
+ type: 'histogram',
102
+ value: sum,
103
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined,
104
+ });
105
+
106
+ // 添加 count
107
+ dataPoints.push({
108
+ name: `${name}_count`,
109
+ type: 'histogram',
110
+ value: count,
111
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined,
112
+ });
113
+
114
+ // 添加 buckets
115
+ for (const [bucket, bucketCount] of Object.entries(buckets)) {
116
+ dataPoints.push({
117
+ name: `${name}_bucket`,
118
+ type: 'histogram',
119
+ value: bucketCount,
120
+ labels: {
121
+ ...labels,
122
+ le: bucket,
123
+ },
124
+ });
125
+ }
126
+ }
127
+ }
128
+
129
+ // 收集自定义指标
130
+ for (const metric of this.customMetrics) {
131
+ try {
132
+ const value = await metric.getValue();
133
+ dataPoints.push({
134
+ name: metric.name,
135
+ type: metric.type,
136
+ value,
137
+ help: metric.help,
138
+ });
139
+ } catch (error) {
140
+ // 忽略自定义指标错误
141
+ console.error(`Failed to collect custom metric ${metric.name}:`, error);
142
+ }
143
+ }
144
+
145
+ return dataPoints;
146
+ }
147
+
148
+ /**
149
+ * 重置所有指标
150
+ */
151
+ public reset(): void {
152
+ this.counters.clear();
153
+ this.gauges.clear();
154
+ this.histograms.clear();
155
+ }
156
+
157
+ /**
158
+ * 生成标签键
159
+ */
160
+ private getKey(name: string, labels?: MetricLabels): string {
161
+ if (!labels || Object.keys(labels).length === 0) {
162
+ return '';
163
+ }
164
+
165
+ const sortedLabels = Object.keys(labels)
166
+ .sort()
167
+ .map((key) => `${key}="${labels[key]}"`)
168
+ .join(',');
169
+ return `{${sortedLabels}}`;
170
+ }
171
+
172
+ /**
173
+ * 解析标签键
174
+ */
175
+ private parseKey(key: string): MetricLabels | undefined {
176
+ if (!key || key === '') {
177
+ return undefined;
178
+ }
179
+
180
+ const labels: MetricLabels = {};
181
+ const match = key.match(/\{([^}]+)\}/);
182
+ if (match) {
183
+ const labelPairs = match[1].split(',');
184
+ for (const pair of labelPairs) {
185
+ const [k, v] = pair.split('=');
186
+ if (k && v) {
187
+ labels[k.trim()] = v.trim().replace(/^"|"$/g, '');
188
+ }
189
+ }
190
+ }
191
+ return Object.keys(labels).length > 0 ? labels : undefined;
192
+ }
193
+
194
+ /**
195
+ * 计算直方图桶
196
+ */
197
+ private calculateBuckets(values: number[]): Record<string, number> {
198
+ // Prometheus 默认桶:.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, +Inf
199
+ const defaultBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];
200
+ const buckets: Record<string, number> = {};
201
+
202
+ for (const bucket of defaultBuckets) {
203
+ buckets[bucket.toString()] = values.filter((v) => v <= bucket).length;
204
+ }
205
+ buckets['+Inf'] = values.length;
206
+
207
+ return buckets;
208
+ }
209
+ }
@@ -0,0 +1,40 @@
1
+ import { GET } from '../router/decorators';
2
+ import { Inject } from '../di/decorators';
3
+ import { Controller } from '../controller';
4
+
5
+ import { MetricsCollector } from './collector';
6
+ import { PrometheusFormatter } from './prometheus';
7
+ import { METRICS_SERVICE_TOKEN, METRICS_OPTIONS_TOKEN, type MetricsModuleOptions } from './types';
8
+
9
+ /**
10
+ * Metrics 控制器
11
+ * 提供 `/metrics` 端点用于 Prometheus 指标导出
12
+ */
13
+ @Controller('/')
14
+ export class MetricsController {
15
+ private readonly formatter: PrometheusFormatter;
16
+
17
+ public constructor(
18
+ @Inject(METRICS_SERVICE_TOKEN)
19
+ private readonly collector: MetricsCollector,
20
+ @Inject(METRICS_OPTIONS_TOKEN)
21
+ private readonly options?: MetricsModuleOptions,
22
+ ) {
23
+ this.formatter = new PrometheusFormatter();
24
+ }
25
+
26
+ /**
27
+ * 获取 Prometheus 格式的指标
28
+ */
29
+ @GET('/metrics')
30
+ public async metrics(): Promise<Response> {
31
+ const dataPoints = await this.collector.getAllDataPoints();
32
+ const prometheusText = this.formatter.format(dataPoints);
33
+
34
+ return new Response(prometheusText, {
35
+ headers: {
36
+ 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
37
+ },
38
+ });
39
+ }
40
+ }
@@ -0,0 +1,15 @@
1
+ export { MetricsModule } from './metrics-module';
2
+ export { MetricsCollector } from './collector';
3
+ export { PrometheusFormatter } from './prometheus';
4
+ export { MetricsController } from './controller';
5
+ export { createHttpMetricsMiddleware } from './middleware';
6
+ export {
7
+ METRICS_SERVICE_TOKEN,
8
+ METRICS_OPTIONS_TOKEN,
9
+ type MetricsModuleOptions,
10
+ type MetricType,
11
+ type MetricLabels,
12
+ type MetricValue,
13
+ type MetricDataPoint,
14
+ type CustomMetric,
15
+ } from './types';