@dangao/bun-server 1.2.0 → 1.4.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.
Files changed (162) hide show
  1. package/README.md +15 -0
  2. package/dist/config/config-module.d.ts +17 -0
  3. package/dist/config/config-module.d.ts.map +1 -1
  4. package/dist/config/service.d.ts +18 -1
  5. package/dist/config/service.d.ts.map +1 -1
  6. package/dist/config/types.d.ts +25 -0
  7. package/dist/config/types.d.ts.map +1 -1
  8. package/dist/controller/controller.d.ts +5 -0
  9. package/dist/controller/controller.d.ts.map +1 -1
  10. package/dist/controller/decorators.d.ts +30 -1
  11. package/dist/controller/decorators.d.ts.map +1 -1
  12. package/dist/controller/index.d.ts +2 -2
  13. package/dist/controller/index.d.ts.map +1 -1
  14. package/dist/controller/param-binder.d.ts +12 -0
  15. package/dist/controller/param-binder.d.ts.map +1 -1
  16. package/dist/core/application.d.ts +15 -0
  17. package/dist/core/application.d.ts.map +1 -1
  18. package/dist/core/context.d.ts +1 -0
  19. package/dist/core/context.d.ts.map +1 -1
  20. package/dist/core/server.d.ts +8 -0
  21. package/dist/core/server.d.ts.map +1 -1
  22. package/dist/index.d.ts +8 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +6487 -4178
  25. package/dist/microservice/config-center/config-center-module.d.ts +43 -0
  26. package/dist/microservice/config-center/config-center-module.d.ts.map +1 -0
  27. package/dist/microservice/config-center/decorators.d.ts +58 -0
  28. package/dist/microservice/config-center/decorators.d.ts.map +1 -0
  29. package/dist/microservice/config-center/index.d.ts +9 -0
  30. package/dist/microservice/config-center/index.d.ts.map +1 -0
  31. package/dist/microservice/config-center/nacos-config-center.d.ts +37 -0
  32. package/dist/microservice/config-center/nacos-config-center.d.ts.map +1 -0
  33. package/dist/microservice/config-center/nacos-decorators.d.ts +24 -0
  34. package/dist/microservice/config-center/nacos-decorators.d.ts.map +1 -0
  35. package/dist/microservice/config-center/types.d.ts +63 -0
  36. package/dist/microservice/config-center/types.d.ts.map +1 -0
  37. package/dist/microservice/governance/circuit-breaker.d.ts +54 -0
  38. package/dist/microservice/governance/circuit-breaker.d.ts.map +1 -0
  39. package/dist/microservice/governance/decorators.d.ts +51 -0
  40. package/dist/microservice/governance/decorators.d.ts.map +1 -0
  41. package/dist/microservice/governance/index.d.ts +9 -0
  42. package/dist/microservice/governance/index.d.ts.map +1 -0
  43. package/dist/microservice/governance/rate-limiter.d.ts +26 -0
  44. package/dist/microservice/governance/rate-limiter.d.ts.map +1 -0
  45. package/dist/microservice/governance/redis-rate-limiter.d.ts +76 -0
  46. package/dist/microservice/governance/redis-rate-limiter.d.ts.map +1 -0
  47. package/dist/microservice/governance/retry-strategy.d.ts +21 -0
  48. package/dist/microservice/governance/retry-strategy.d.ts.map +1 -0
  49. package/dist/microservice/governance/types.d.ts +212 -0
  50. package/dist/microservice/governance/types.d.ts.map +1 -0
  51. package/dist/microservice/index.d.ts +10 -0
  52. package/dist/microservice/index.d.ts.map +1 -0
  53. package/dist/microservice/monitoring/index.d.ts +4 -0
  54. package/dist/microservice/monitoring/index.d.ts.map +1 -0
  55. package/dist/microservice/monitoring/metrics-collector.d.ts +54 -0
  56. package/dist/microservice/monitoring/metrics-collector.d.ts.map +1 -0
  57. package/dist/microservice/monitoring/metrics-integration.d.ts +24 -0
  58. package/dist/microservice/monitoring/metrics-integration.d.ts.map +1 -0
  59. package/dist/microservice/monitoring/types.d.ts +99 -0
  60. package/dist/microservice/monitoring/types.d.ts.map +1 -0
  61. package/dist/microservice/service-client/call-decorators.d.ts +52 -0
  62. package/dist/microservice/service-client/call-decorators.d.ts.map +1 -0
  63. package/dist/microservice/service-client/decorators.d.ts +35 -0
  64. package/dist/microservice/service-client/decorators.d.ts.map +1 -0
  65. package/dist/microservice/service-client/index.d.ts +7 -0
  66. package/dist/microservice/service-client/index.d.ts.map +1 -0
  67. package/dist/microservice/service-client/interceptors.d.ts +96 -0
  68. package/dist/microservice/service-client/interceptors.d.ts.map +1 -0
  69. package/dist/microservice/service-client/load-balancer.d.ts +59 -0
  70. package/dist/microservice/service-client/load-balancer.d.ts.map +1 -0
  71. package/dist/microservice/service-client/service-client.d.ts +74 -0
  72. package/dist/microservice/service-client/service-client.d.ts.map +1 -0
  73. package/dist/microservice/service-client/types.d.ts +155 -0
  74. package/dist/microservice/service-client/types.d.ts.map +1 -0
  75. package/dist/microservice/service-registry/decorators.d.ts +84 -0
  76. package/dist/microservice/service-registry/decorators.d.ts.map +1 -0
  77. package/dist/microservice/service-registry/discovery-decorators.d.ts +58 -0
  78. package/dist/microservice/service-registry/discovery-decorators.d.ts.map +1 -0
  79. package/dist/microservice/service-registry/health-integration.d.ts +32 -0
  80. package/dist/microservice/service-registry/health-integration.d.ts.map +1 -0
  81. package/dist/microservice/service-registry/index.d.ts +10 -0
  82. package/dist/microservice/service-registry/index.d.ts.map +1 -0
  83. package/dist/microservice/service-registry/nacos-service-registry.d.ts +68 -0
  84. package/dist/microservice/service-registry/nacos-service-registry.d.ts.map +1 -0
  85. package/dist/microservice/service-registry/service-registry-module.d.ts +48 -0
  86. package/dist/microservice/service-registry/service-registry-module.d.ts.map +1 -0
  87. package/dist/microservice/service-registry/types.d.ts +121 -0
  88. package/dist/microservice/service-registry/types.d.ts.map +1 -0
  89. package/dist/microservice/tracing/collectors.d.ts +27 -0
  90. package/dist/microservice/tracing/collectors.d.ts.map +1 -0
  91. package/dist/microservice/tracing/index.d.ts +4 -0
  92. package/dist/microservice/tracing/index.d.ts.map +1 -0
  93. package/dist/microservice/tracing/tracer.d.ts +59 -0
  94. package/dist/microservice/tracing/tracer.d.ts.map +1 -0
  95. package/dist/microservice/tracing/types.d.ts +179 -0
  96. package/dist/microservice/tracing/types.d.ts.map +1 -0
  97. package/dist/request/request.d.ts +1 -0
  98. package/dist/request/request.d.ts.map +1 -1
  99. package/docs/microservice-config-center.md +258 -0
  100. package/docs/microservice-nacos.md +346 -0
  101. package/docs/microservice-service-registry.md +306 -0
  102. package/docs/microservice.md +680 -0
  103. package/docs/troubleshooting.md +41 -0
  104. package/docs/zh/troubleshooting.md +41 -0
  105. package/package.json +5 -4
  106. package/src/config/config-module.ts +210 -0
  107. package/src/config/service.ts +52 -1
  108. package/src/config/types.ts +31 -0
  109. package/src/controller/controller.ts +8 -0
  110. package/src/controller/decorators.ts +55 -0
  111. package/src/controller/index.ts +16 -2
  112. package/src/controller/param-binder.ts +87 -1
  113. package/src/core/application.ts +100 -2
  114. package/src/core/context.ts +1 -0
  115. package/src/core/server.ts +14 -0
  116. package/src/index.ts +98 -2
  117. package/src/microservice/config-center/config-center-module.ts +98 -0
  118. package/src/microservice/config-center/decorators.ts +159 -0
  119. package/src/microservice/config-center/index.ts +13 -0
  120. package/src/microservice/config-center/nacos-config-center.ts +126 -0
  121. package/src/microservice/config-center/nacos-decorators.ts +34 -0
  122. package/src/microservice/config-center/types.ts +80 -0
  123. package/src/microservice/governance/circuit-breaker.ts +229 -0
  124. package/src/microservice/governance/decorators.ts +113 -0
  125. package/src/microservice/governance/index.ts +18 -0
  126. package/src/microservice/governance/rate-limiter.ts +72 -0
  127. package/src/microservice/governance/redis-rate-limiter.ts +154 -0
  128. package/src/microservice/governance/retry-strategy.ts +74 -0
  129. package/src/microservice/governance/types.ts +247 -0
  130. package/src/microservice/index.ts +12 -0
  131. package/src/microservice/monitoring/index.ts +8 -0
  132. package/src/microservice/monitoring/metrics-collector.ts +223 -0
  133. package/src/microservice/monitoring/metrics-integration.ts +154 -0
  134. package/src/microservice/monitoring/types.ts +118 -0
  135. package/src/microservice/service-client/call-decorators.ts +107 -0
  136. package/src/microservice/service-client/decorators.ts +87 -0
  137. package/src/microservice/service-client/index.ts +37 -0
  138. package/src/microservice/service-client/interceptors.ts +182 -0
  139. package/src/microservice/service-client/load-balancer.ts +205 -0
  140. package/src/microservice/service-client/service-client.ts +488 -0
  141. package/src/microservice/service-client/types.ts +186 -0
  142. package/src/microservice/service-registry/decorators.ts +238 -0
  143. package/src/microservice/service-registry/discovery-decorators.ts +156 -0
  144. package/src/microservice/service-registry/health-integration.ts +146 -0
  145. package/src/microservice/service-registry/index.ts +20 -0
  146. package/src/microservice/service-registry/nacos-service-registry.ts +259 -0
  147. package/src/microservice/service-registry/service-registry-module.ts +105 -0
  148. package/src/microservice/service-registry/types.ts +149 -0
  149. package/src/microservice/tracing/collectors.ts +50 -0
  150. package/src/microservice/tracing/index.ts +15 -0
  151. package/src/microservice/tracing/tracer.ts +293 -0
  152. package/src/microservice/tracing/types.ts +213 -0
  153. package/src/request/request.ts +1 -0
  154. package/tests/config/set-value-by-path.test.ts +53 -0
  155. package/tests/controller/param-map.test.ts +237 -0
  156. package/tests/microservice/config-center.test.ts +77 -0
  157. package/tests/microservice/governance.test.ts +157 -0
  158. package/tests/microservice/monitoring.test.ts +75 -0
  159. package/tests/microservice/service-client.test.ts +136 -0
  160. package/tests/microservice/service-registry.test.ts +80 -0
  161. package/tests/microservice/tracing.test.ts +143 -0
  162. package/tests/utils/test-port.ts +29 -19
@@ -13,6 +13,9 @@ import { ModuleRegistry } from '../di/module-registry';
13
13
  import type { ModuleClass } from '../di/module';
14
14
  import type { Constructor } from './types';
15
15
  import { InterceptorRegistry, INTERCEPTOR_REGISTRY_TOKEN } from '../interceptor';
16
+ import { CONFIG_SERVICE_TOKEN } from '../config/types';
17
+ import { ConfigService } from '../config/service';
18
+ import { ConfigModule } from '../config/config-module';
16
19
 
17
20
  /**
18
21
  * 应用配置选项
@@ -81,15 +84,24 @@ export class Application {
81
84
  // 初始化所有扩展(包括数据库连接等)
82
85
  await this.initializeExtensions();
83
86
 
87
+ // 初始化配置中心集成(在所有模块注册完成后)
88
+ await this.initializeConfigCenter();
89
+
90
+ const finalPort = port ?? this.options.port ?? 3000;
91
+ const finalHostname = hostname ?? this.options.hostname;
92
+
84
93
  const serverOptions: ServerOptions = {
85
- port: port ?? this.options.port ?? 3000,
86
- hostname: hostname ?? this.options.hostname,
94
+ port: finalPort,
95
+ hostname: finalHostname,
87
96
  fetch: this.handleRequest.bind(this),
88
97
  websocketRegistry: this.websocketRegistry,
89
98
  };
90
99
 
91
100
  this.server = new BunServer(serverOptions);
92
101
  this.server.start();
102
+
103
+ // 自动注册服务到注册中心(如果使用了 @ServiceRegistry 装饰器)
104
+ await this.registerServices(finalPort, finalHostname);
93
105
  }
94
106
 
95
107
  /**
@@ -116,10 +128,42 @@ export class Application {
116
128
  // 所以上面的循环已经处理了
117
129
  }
118
130
 
131
+ /**
132
+ * 初始化配置中心集成
133
+ * 在所有模块注册完成后调用,确保 ConfigCenterModule 已注册
134
+ */
135
+ private async initializeConfigCenter(): Promise<void> {
136
+ const container = this.getContainer();
137
+ // ConfigModule 可能未注册(很多测试/应用不使用配置模块),此时不要抛错
138
+ if (!container.isRegistered(CONFIG_SERVICE_TOKEN)) {
139
+ return;
140
+ }
141
+
142
+ const configService = container.resolve<ConfigService>(CONFIG_SERVICE_TOKEN);
143
+
144
+ // 检查是否有待初始化的配置中心选项
145
+ const configCenterOptions = (configService as any)._configCenterOptions;
146
+ if (configCenterOptions) {
147
+ try {
148
+ await ConfigModule.initializeConfigCenter(configService, configCenterOptions);
149
+ // 清除临时选项
150
+ delete (configService as any)._configCenterOptions;
151
+ } catch (error) {
152
+ console.error(
153
+ '[Application] Failed to initialize config center:',
154
+ error,
155
+ );
156
+ }
157
+ }
158
+ }
159
+
119
160
  /**
120
161
  * 停止应用
121
162
  */
122
163
  public async stop(): Promise<void> {
164
+ // 自动注销服务(如果使用了 @ServiceRegistry 装饰器)
165
+ await this.deregisterServices();
166
+
123
167
  // 关闭所有扩展(包括数据库连接等)
124
168
  await this.closeExtensions();
125
169
  this.server?.stop();
@@ -235,6 +279,60 @@ export class Application {
235
279
  return this.server;
236
280
  }
237
281
 
282
+ /**
283
+ * 自动注册服务到注册中心
284
+ * 扫描所有使用 @ServiceRegistry 装饰器的控制器,自动注册服务
285
+ */
286
+ private async registerServices(port: number, hostname?: string): Promise<void> {
287
+ try {
288
+ // 动态导入服务注册装饰器(避免循环依赖)
289
+ const { registerServiceInstance } = await import(
290
+ '../microservice/service-registry/decorators'
291
+ );
292
+
293
+ const registry = ControllerRegistry.getInstance();
294
+ const controllers = registry.getRegisteredControllers();
295
+
296
+ for (const controllerClass of controllers) {
297
+ await registerServiceInstance(controllerClass, port, hostname);
298
+ }
299
+ } catch (error) {
300
+ // 如果服务注册失败,不影响应用启动(可能是没有配置 ServiceRegistryModule)
301
+ // 只在调试模式下输出警告
302
+ if (process.env.NODE_ENV === 'development') {
303
+ console.warn('[Application] Failed to register services:', error);
304
+ }
305
+ }
306
+ }
307
+
308
+ /**
309
+ * 自动注销服务
310
+ * 注销所有使用 @ServiceRegistry 装饰器的服务
311
+ */
312
+ private async deregisterServices(): Promise<void> {
313
+ try {
314
+ // 动态导入服务注册装饰器(避免循环依赖)
315
+ const { deregisterServiceInstance } = await import(
316
+ '../microservice/service-registry/decorators'
317
+ );
318
+
319
+ const registry = ControllerRegistry.getInstance();
320
+ const controllers = registry.getRegisteredControllers();
321
+
322
+ const port = this.server?.getPort() ?? this.options.port ?? 3000;
323
+ const hostname = this.server?.getHostname() ?? this.options.hostname;
324
+
325
+ for (const controllerClass of controllers) {
326
+ await deregisterServiceInstance(controllerClass, port, hostname);
327
+ }
328
+ } catch (error) {
329
+ // 如果服务注销失败,不影响应用关闭
330
+ if (process.env.NODE_ENV === 'development') {
331
+ console.warn('[Application] Failed to deregister services:', error);
332
+ }
333
+ }
334
+ }
335
+
238
336
  /**
239
337
  * 获取 DI 容器(用于注册服务)
240
338
  * @returns DI 容器
@@ -1,6 +1,7 @@
1
1
  import { BodyParser } from '../request/body-parser';
2
2
  import type { UploadedFileInfo } from '../files';
3
3
  import type { BodyInit } from 'bun'
4
+ import { type URLSearchParams, URL } from 'url';
4
5
 
5
6
  /**
6
7
  * 请求上下文
@@ -125,4 +125,18 @@ export class BunServer {
125
125
  public isRunning(): boolean {
126
126
  return this.server !== undefined;
127
127
  }
128
+
129
+ /**
130
+ * 获取服务器端口
131
+ */
132
+ public getPort(): number {
133
+ return this.options.port ?? 3000;
134
+ }
135
+
136
+ /**
137
+ * 获取服务器主机名
138
+ */
139
+ public getHostname(): string | undefined {
140
+ return this.options.hostname;
141
+ }
128
142
  }
package/src/index.ts CHANGED
@@ -6,9 +6,24 @@ export { Route, Router, RouteRegistry } from './router';
6
6
  export { GET, POST, PUT, DELETE, PATCH } from './router/decorators';
7
7
  export type { HttpMethod, RouteHandler, RouteMatch } from './router/types';
8
8
  export { BodyParser, RequestWrapper, ResponseBuilder } from './request';
9
- export { Body, Query, Param, Header, ParamBinder, Controller, ControllerRegistry } from './controller';
9
+ export {
10
+ Body,
11
+ Query,
12
+ QueryMap,
13
+ Param,
14
+ Header,
15
+ HeaderMap,
16
+ ParamBinder,
17
+ Controller,
18
+ ControllerRegistry,
19
+ } from './controller';
10
20
  export { Context as ContextParam } from './controller';
11
- export type { ParamMetadata, ControllerMetadata } from './controller';
21
+ export type {
22
+ ParamMetadata,
23
+ QueryMapOptions,
24
+ HeaderMapOptions,
25
+ ControllerMetadata,
26
+ } from './controller';
12
27
  export { Container } from './di/container';
13
28
  export { Injectable, Inject } from './di/decorators';
14
29
  export { Lifecycle, type ProviderConfig, type DependencyMetadata } from './di/types';
@@ -291,4 +306,85 @@ export type {
291
306
  SessionData,
292
307
  RedisSessionStoreOptions,
293
308
  } from './session';
309
+ // Microservice 模块
310
+ export {
311
+ ConfigCenterModule,
312
+ NacosConfigCenter,
313
+ CONFIG_CENTER_TOKEN,
314
+ type ConfigCenterModuleOptions,
315
+ type ConfigCenterProvider,
316
+ type NacosConfigCenterOptions,
317
+ type ConfigCenter,
318
+ type ConfigChangeListener,
319
+ type ConfigResult,
320
+ } from './microservice';
321
+ export {
322
+ ServiceRegistryModule,
323
+ NacosServiceRegistry,
324
+ SERVICE_REGISTRY_TOKEN,
325
+ type ServiceRegistryModuleOptions,
326
+ type ServiceRegistryProvider,
327
+ type NacosServiceRegistryOptions,
328
+ type ServiceRegistry,
329
+ type GetInstancesOptions,
330
+ type InstancesChangeListener,
331
+ type ServiceInstance,
332
+ } from './microservice';
333
+ // Service Client 模块
334
+ export {
335
+ ServiceClient,
336
+ LoadBalancerFactory,
337
+ RandomLoadBalancer,
338
+ RoundRobinLoadBalancer,
339
+ WeightedRoundRobinLoadBalancer,
340
+ ConsistentHashLoadBalancer,
341
+ LeastActiveLoadBalancer,
342
+ TraceIdRequestInterceptor,
343
+ UserInfoRequestInterceptor,
344
+ RequestLogInterceptor,
345
+ ResponseLogInterceptor,
346
+ ResponseTransformInterceptor,
347
+ ErrorHandlerInterceptor,
348
+ type LoadBalanceStrategy,
349
+ type LoadBalancer,
350
+ type ServiceCallOptions,
351
+ type ServiceCallResponse,
352
+ type ServiceRequestInterceptor,
353
+ type ServiceResponseInterceptor,
354
+ type ServiceCallError,
355
+ } from './microservice';
356
+ // Governance 模块
357
+ export {
358
+ CircuitBreaker,
359
+ CircuitBreakerState,
360
+ RateLimiter,
361
+ RetryStrategyImpl,
362
+ type CircuitBreakerOptions,
363
+ type CircuitBreakerStats,
364
+ type RateLimiterOptions,
365
+ type RetryStrategy,
366
+ } from './microservice';
367
+ // Tracing 模块
368
+ export {
369
+ Tracer,
370
+ ConsoleTraceCollector,
371
+ MemoryTraceCollector,
372
+ SpanStatus,
373
+ SpanKind,
374
+ type TraceId,
375
+ type SpanId,
376
+ type SpanContext,
377
+ type Span,
378
+ type SpanTags,
379
+ type SpanEvent,
380
+ type TracingOptions,
381
+ type TraceCollector,
382
+ } from './microservice';
383
+ // Monitoring 模块
384
+ export {
385
+ ServiceMetricsCollector,
386
+ type ServiceCallMetrics,
387
+ type ServiceInstanceHealth,
388
+ type MonitoringOptions,
389
+ } from './microservice';
294
390
 
@@ -0,0 +1,98 @@
1
+ import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../../di/module';
2
+ import { NacosClient } from '@dangao/nacos-client';
3
+ import type { NacosClientOptions } from '@dangao/nacos-client';
4
+ import { NacosConfigCenter } from './nacos-config-center';
5
+ import { CONFIG_CENTER_TOKEN, type ConfigCenter } from './types';
6
+
7
+ /**
8
+ * 配置中心 Provider 类型
9
+ */
10
+ export type ConfigCenterProvider = 'nacos' | 'consul' | 'etcd' | 'apollo';
11
+
12
+ /**
13
+ * Nacos 配置中心选项
14
+ */
15
+ export interface NacosConfigCenterOptions {
16
+ /**
17
+ * Nacos 客户端配置
18
+ */
19
+ client: NacosClientOptions;
20
+
21
+ /**
22
+ * 配置监听轮询间隔(毫秒)
23
+ * @default 3000
24
+ */
25
+ watchInterval?: number;
26
+ }
27
+
28
+ /**
29
+ * 配置中心模块选项
30
+ */
31
+ export interface ConfigCenterModuleOptions {
32
+ /**
33
+ * Provider 类型
34
+ */
35
+ provider: ConfigCenterProvider;
36
+
37
+ /**
38
+ * Nacos 配置(当 provider 为 'nacos' 时使用)
39
+ */
40
+ nacos?: NacosConfigCenterOptions;
41
+
42
+ // 未来可以添加其他 provider 的配置
43
+ // consul?: ConsulConfigCenterOptions;
44
+ // etcd?: EtcdConfigCenterOptions;
45
+ }
46
+
47
+ /**
48
+ * 配置中心模块
49
+ */
50
+ @Module({
51
+ providers: [],
52
+ })
53
+ export class ConfigCenterModule {
54
+ /**
55
+ * 创建配置中心模块
56
+ * @param options - 模块配置
57
+ */
58
+ public static forRoot(options: ConfigCenterModuleOptions): typeof ConfigCenterModule {
59
+ const providers: ModuleProvider[] = [];
60
+
61
+ let configCenter: ConfigCenter;
62
+
63
+ switch (options.provider) {
64
+ case 'nacos':
65
+ if (!options.nacos) {
66
+ throw new Error('Nacos configuration is required when provider is "nacos"');
67
+ }
68
+
69
+ const nacosClient = new NacosClient(options.nacos.client);
70
+ configCenter = new NacosConfigCenter(nacosClient, {
71
+ watchInterval: options.nacos.watchInterval,
72
+ });
73
+ break;
74
+
75
+ default:
76
+ throw new Error(`Unsupported config center provider: ${options.provider}`);
77
+ }
78
+
79
+ providers.push({
80
+ provide: CONFIG_CENTER_TOKEN,
81
+ useValue: configCenter,
82
+ });
83
+
84
+ const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, ConfigCenterModule) || {};
85
+ const metadata = {
86
+ ...existingMetadata,
87
+ providers: [...(existingMetadata.providers || []), ...providers],
88
+ exports: [
89
+ ...(existingMetadata.exports || []),
90
+ CONFIG_CENTER_TOKEN,
91
+ ],
92
+ };
93
+ Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, ConfigCenterModule);
94
+
95
+ return ConfigCenterModule;
96
+ }
97
+ }
98
+
@@ -0,0 +1,159 @@
1
+ import 'reflect-metadata';
2
+ import type { ConfigCenter } from './types';
3
+ import { CONFIG_CENTER_TOKEN } from './types';
4
+ import { ControllerRegistry } from '../../controller/controller';
5
+ import type { Constructor } from '../../core/types';
6
+
7
+ /**
8
+ * 配置中心值装饰器元数据键
9
+ */
10
+ const CONFIG_CENTER_VALUE_METADATA_KEY = Symbol('config-center:value');
11
+
12
+ /**
13
+ * 配置中心值元数据
14
+ */
15
+ export interface ConfigCenterValueMetadata {
16
+ /**
17
+ * 配置 dataId
18
+ */
19
+ dataId: string;
20
+
21
+ /**
22
+ * 配置分组
23
+ */
24
+ groupName: string;
25
+
26
+ /**
27
+ * 命名空间(可选)
28
+ */
29
+ namespaceId?: string;
30
+
31
+ /**
32
+ * 默认值(可选)
33
+ */
34
+ defaultValue?: string;
35
+
36
+ /**
37
+ * 是否监听配置变更
38
+ */
39
+ watch?: boolean;
40
+ }
41
+
42
+ /**
43
+ * ConfigCenterValue 装饰器
44
+ * 用于自动注入配置中心的值
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * @Injectable()
49
+ * class MyService {
50
+ * @ConfigCenterValue('my-config', 'DEFAULT_GROUP')
51
+ * public configValue: string = '';
52
+ *
53
+ * @ConfigCenterValue('app-name', 'DEFAULT_GROUP', { defaultValue: 'MyApp' })
54
+ * public appName: string = '';
55
+ * }
56
+ * ```
57
+ */
58
+ export function ConfigCenterValue(
59
+ dataId: string,
60
+ groupName: string = 'DEFAULT_GROUP',
61
+ options?: {
62
+ namespaceId?: string;
63
+ defaultValue?: string;
64
+ watch?: boolean;
65
+ },
66
+ ): PropertyDecorator {
67
+ return function (target: object, propertyKey: string | symbol) {
68
+ const metadata: ConfigCenterValueMetadata = {
69
+ dataId,
70
+ groupName,
71
+ namespaceId: options?.namespaceId,
72
+ defaultValue: options?.defaultValue,
73
+ watch: options?.watch ?? false,
74
+ };
75
+
76
+ // 保存元数据
77
+ const existingMetadata: Map<string | symbol, ConfigCenterValueMetadata> =
78
+ Reflect.getMetadata(CONFIG_CENTER_VALUE_METADATA_KEY, target.constructor) ||
79
+ new Map();
80
+ existingMetadata.set(propertyKey, metadata);
81
+ Reflect.defineMetadata(
82
+ CONFIG_CENTER_VALUE_METADATA_KEY,
83
+ existingMetadata,
84
+ target.constructor,
85
+ );
86
+
87
+ // 定义属性描述符,实现自动注入
88
+ // 注意:属性 getter 必须是同步的,不能是 async
89
+ // 实际值通过 initializeConfigCenterValues 在实例化时预加载
90
+ let value: string | undefined = options?.defaultValue;
91
+
92
+ Object.defineProperty(target, propertyKey, {
93
+ get: () => {
94
+ // 同步返回已加载的值(如果还未加载,返回默认值)
95
+ return value ?? options?.defaultValue ?? '';
96
+ },
97
+ set: (newValue: string) => {
98
+ value = newValue;
99
+ },
100
+ enumerable: true,
101
+ configurable: true,
102
+ });
103
+ };
104
+ }
105
+
106
+ /**
107
+ * 获取类的所有配置中心值元数据
108
+ */
109
+ export function getConfigCenterValueMetadata(
110
+ target: Constructor<unknown>,
111
+ ): Map<string | symbol, ConfigCenterValueMetadata> {
112
+ return (
113
+ Reflect.getMetadata(CONFIG_CENTER_VALUE_METADATA_KEY, target) || new Map()
114
+ );
115
+ }
116
+
117
+ /**
118
+ * 初始化类的配置中心值
119
+ * 在类实例化后调用,自动加载配置值
120
+ */
121
+ export async function initializeConfigCenterValues(
122
+ instance: object,
123
+ target: Constructor<unknown>,
124
+ ): Promise<void> {
125
+ const metadata = getConfigCenterValueMetadata(target);
126
+ const container = ControllerRegistry.getInstance().getContainer();
127
+ const configCenter = container.resolve<ConfigCenter>(CONFIG_CENTER_TOKEN);
128
+
129
+ if (!configCenter) {
130
+ return;
131
+ }
132
+
133
+ for (const [propertyKey, meta] of metadata.entries()) {
134
+ try {
135
+ const result = await configCenter.getConfig(
136
+ meta.dataId,
137
+ meta.groupName,
138
+ meta.namespaceId,
139
+ );
140
+ (instance as any)[propertyKey] = result.content;
141
+
142
+ // 如果启用监听,设置监听器
143
+ if (meta.watch) {
144
+ configCenter.watchConfig(meta.dataId, meta.groupName, (newResult: any) => {
145
+ (instance as any)[propertyKey] = newResult.content;
146
+ });
147
+ }
148
+ } catch (error) {
149
+ console.error(
150
+ `[ConfigCenterValue] Failed to initialize config ${meta.dataId}:`,
151
+ error,
152
+ );
153
+ if (meta.defaultValue !== undefined) {
154
+ (instance as any)[propertyKey] = meta.defaultValue;
155
+ }
156
+ }
157
+ }
158
+ }
159
+
@@ -0,0 +1,13 @@
1
+ export { ConfigCenterModule } from './config-center-module';
2
+ export type { ConfigCenterModuleOptions, ConfigCenterProvider, NacosConfigCenterOptions } from './config-center-module';
3
+ export { NacosConfigCenter } from './nacos-config-center';
4
+ export { CONFIG_CENTER_TOKEN } from './types';
5
+ export type { ConfigCenter, ConfigChangeListener, ConfigResult } from './types';
6
+ export {
7
+ ConfigCenterValue,
8
+ getConfigCenterValueMetadata,
9
+ initializeConfigCenterValues,
10
+ } from './decorators';
11
+ export { NacosValue } from './nacos-decorators';
12
+ export type { ConfigCenterValueMetadata } from './decorators';
13
+
@@ -0,0 +1,126 @@
1
+ import { NacosClient, NacosConfigClient } from '@dangao/nacos-client';
2
+ import type { ConfigResult, ConfigChangeListener, ConfigCenter } from './types';
3
+
4
+ /**
5
+ * Nacos 配置中心实现
6
+ * 实现 ConfigCenter 接口,内部使用 @dangao/nacos-client
7
+ */
8
+ export class NacosConfigCenter implements ConfigCenter {
9
+ private readonly client: NacosClient;
10
+ private readonly configClient: NacosConfigClient;
11
+ private readonly watchers: Map<string, { listener: ConfigChangeListener; intervalId: number }> = new Map();
12
+ private readonly watchInterval: number = 3000; // 默认 3 秒轮询一次
13
+
14
+ public constructor(
15
+ client: NacosClient,
16
+ options?: {
17
+ /**
18
+ * 配置监听轮询间隔(毫秒)
19
+ * @default 3000
20
+ */
21
+ watchInterval?: number;
22
+ },
23
+ ) {
24
+ this.client = client;
25
+ this.configClient = new NacosConfigClient(client);
26
+ this.watchInterval = options?.watchInterval ?? 3000;
27
+ }
28
+
29
+ /**
30
+ * 获取配置
31
+ */
32
+ public async getConfig(
33
+ dataId: string,
34
+ groupName: string,
35
+ namespaceId?: string,
36
+ ): Promise<ConfigResult> {
37
+ const result = await this.configClient.getConfig({
38
+ dataId,
39
+ groupName,
40
+ namespaceId,
41
+ });
42
+
43
+ return {
44
+ content: result.content,
45
+ md5: result.md5,
46
+ lastModified: result.lastModified,
47
+ contentType: result.contentType,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * 监听配置变更
53
+ * 通过轮询和 md5 比对实现配置热更新
54
+ */
55
+ public watchConfig(
56
+ dataId: string,
57
+ groupName: string,
58
+ listener: ConfigChangeListener,
59
+ namespaceId?: string,
60
+ ): () => void {
61
+ const key = this.getWatchKey(dataId, groupName, namespaceId);
62
+
63
+ // 如果已经存在监听器,先取消
64
+ const existing = this.watchers.get(key);
65
+ if (existing) {
66
+ clearInterval(existing.intervalId);
67
+ }
68
+
69
+ let lastMd5: string | undefined;
70
+
71
+ const intervalId = setInterval(async () => {
72
+ try {
73
+ const result = await this.getConfig(dataId, groupName, namespaceId);
74
+
75
+ // 通过 md5 判断配置是否变更
76
+ if (lastMd5 === undefined || lastMd5 !== result.md5) {
77
+ lastMd5 = result.md5;
78
+ listener(result);
79
+ }
80
+ } catch (error) {
81
+ // 监听错误不抛出,避免影响其他监听器
82
+ console.error(`[NacosConfigCenter] Failed to watch config ${dataId}:`, error);
83
+ }
84
+ }, this.watchInterval) as unknown as number;
85
+
86
+ // 立即获取一次配置
87
+ this.getConfig(dataId, groupName, namespaceId)
88
+ .then((result) => {
89
+ lastMd5 = result.md5;
90
+ listener(result);
91
+ })
92
+ .catch((error) => {
93
+ console.error(`[NacosConfigCenter] Failed to get initial config ${dataId}:`, error);
94
+ });
95
+
96
+ this.watchers.set(key, { listener, intervalId });
97
+
98
+ // 返回取消监听的函数
99
+ return () => {
100
+ const watcher = this.watchers.get(key);
101
+ if (watcher) {
102
+ clearInterval(watcher.intervalId);
103
+ this.watchers.delete(key);
104
+ }
105
+ };
106
+ }
107
+
108
+ /**
109
+ * 关闭配置中心连接
110
+ */
111
+ public async close(): Promise<void> {
112
+ // 清除所有监听器
113
+ for (const watcher of this.watchers.values()) {
114
+ clearInterval(watcher.intervalId);
115
+ }
116
+ this.watchers.clear();
117
+ }
118
+
119
+ /**
120
+ * 生成监听器 key
121
+ */
122
+ private getWatchKey(dataId: string, groupName: string, namespaceId?: string): string {
123
+ return `${namespaceId ?? 'default'}:${groupName}:${dataId}`;
124
+ }
125
+ }
126
+