@dangao/bun-server 1.3.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.
- package/README.md +15 -0
- package/dist/config/config-module.d.ts +17 -0
- package/dist/config/config-module.d.ts.map +1 -1
- package/dist/config/service.d.ts +18 -1
- package/dist/config/service.d.ts.map +1 -1
- package/dist/config/types.d.ts +25 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/controller/controller.d.ts +5 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/core/application.d.ts +15 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/context.d.ts +1 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/server.d.ts +8 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6418 -4177
- package/dist/microservice/config-center/config-center-module.d.ts +43 -0
- package/dist/microservice/config-center/config-center-module.d.ts.map +1 -0
- package/dist/microservice/config-center/decorators.d.ts +58 -0
- package/dist/microservice/config-center/decorators.d.ts.map +1 -0
- package/dist/microservice/config-center/index.d.ts +9 -0
- package/dist/microservice/config-center/index.d.ts.map +1 -0
- package/dist/microservice/config-center/nacos-config-center.d.ts +37 -0
- package/dist/microservice/config-center/nacos-config-center.d.ts.map +1 -0
- package/dist/microservice/config-center/nacos-decorators.d.ts +24 -0
- package/dist/microservice/config-center/nacos-decorators.d.ts.map +1 -0
- package/dist/microservice/config-center/types.d.ts +63 -0
- package/dist/microservice/config-center/types.d.ts.map +1 -0
- package/dist/microservice/governance/circuit-breaker.d.ts +54 -0
- package/dist/microservice/governance/circuit-breaker.d.ts.map +1 -0
- package/dist/microservice/governance/decorators.d.ts +51 -0
- package/dist/microservice/governance/decorators.d.ts.map +1 -0
- package/dist/microservice/governance/index.d.ts +9 -0
- package/dist/microservice/governance/index.d.ts.map +1 -0
- package/dist/microservice/governance/rate-limiter.d.ts +26 -0
- package/dist/microservice/governance/rate-limiter.d.ts.map +1 -0
- package/dist/microservice/governance/redis-rate-limiter.d.ts +76 -0
- package/dist/microservice/governance/redis-rate-limiter.d.ts.map +1 -0
- package/dist/microservice/governance/retry-strategy.d.ts +21 -0
- package/dist/microservice/governance/retry-strategy.d.ts.map +1 -0
- package/dist/microservice/governance/types.d.ts +212 -0
- package/dist/microservice/governance/types.d.ts.map +1 -0
- package/dist/microservice/index.d.ts +10 -0
- package/dist/microservice/index.d.ts.map +1 -0
- package/dist/microservice/monitoring/index.d.ts +4 -0
- package/dist/microservice/monitoring/index.d.ts.map +1 -0
- package/dist/microservice/monitoring/metrics-collector.d.ts +54 -0
- package/dist/microservice/monitoring/metrics-collector.d.ts.map +1 -0
- package/dist/microservice/monitoring/metrics-integration.d.ts +24 -0
- package/dist/microservice/monitoring/metrics-integration.d.ts.map +1 -0
- package/dist/microservice/monitoring/types.d.ts +99 -0
- package/dist/microservice/monitoring/types.d.ts.map +1 -0
- package/dist/microservice/service-client/call-decorators.d.ts +52 -0
- package/dist/microservice/service-client/call-decorators.d.ts.map +1 -0
- package/dist/microservice/service-client/decorators.d.ts +35 -0
- package/dist/microservice/service-client/decorators.d.ts.map +1 -0
- package/dist/microservice/service-client/index.d.ts +7 -0
- package/dist/microservice/service-client/index.d.ts.map +1 -0
- package/dist/microservice/service-client/interceptors.d.ts +96 -0
- package/dist/microservice/service-client/interceptors.d.ts.map +1 -0
- package/dist/microservice/service-client/load-balancer.d.ts +59 -0
- package/dist/microservice/service-client/load-balancer.d.ts.map +1 -0
- package/dist/microservice/service-client/service-client.d.ts +74 -0
- package/dist/microservice/service-client/service-client.d.ts.map +1 -0
- package/dist/microservice/service-client/types.d.ts +155 -0
- package/dist/microservice/service-client/types.d.ts.map +1 -0
- package/dist/microservice/service-registry/decorators.d.ts +84 -0
- package/dist/microservice/service-registry/decorators.d.ts.map +1 -0
- package/dist/microservice/service-registry/discovery-decorators.d.ts +58 -0
- package/dist/microservice/service-registry/discovery-decorators.d.ts.map +1 -0
- package/dist/microservice/service-registry/health-integration.d.ts +32 -0
- package/dist/microservice/service-registry/health-integration.d.ts.map +1 -0
- package/dist/microservice/service-registry/index.d.ts +10 -0
- package/dist/microservice/service-registry/index.d.ts.map +1 -0
- package/dist/microservice/service-registry/nacos-service-registry.d.ts +68 -0
- package/dist/microservice/service-registry/nacos-service-registry.d.ts.map +1 -0
- package/dist/microservice/service-registry/service-registry-module.d.ts +48 -0
- package/dist/microservice/service-registry/service-registry-module.d.ts.map +1 -0
- package/dist/microservice/service-registry/types.d.ts +121 -0
- package/dist/microservice/service-registry/types.d.ts.map +1 -0
- package/dist/microservice/tracing/collectors.d.ts +27 -0
- package/dist/microservice/tracing/collectors.d.ts.map +1 -0
- package/dist/microservice/tracing/index.d.ts +4 -0
- package/dist/microservice/tracing/index.d.ts.map +1 -0
- package/dist/microservice/tracing/tracer.d.ts +59 -0
- package/dist/microservice/tracing/tracer.d.ts.map +1 -0
- package/dist/microservice/tracing/types.d.ts +179 -0
- package/dist/microservice/tracing/types.d.ts.map +1 -0
- package/dist/request/request.d.ts +1 -0
- package/dist/request/request.d.ts.map +1 -1
- package/docs/microservice-config-center.md +258 -0
- package/docs/microservice-nacos.md +346 -0
- package/docs/microservice-service-registry.md +306 -0
- package/docs/microservice.md +680 -0
- package/docs/troubleshooting.md +41 -0
- package/docs/zh/troubleshooting.md +41 -0
- package/package.json +5 -4
- package/src/config/config-module.ts +210 -0
- package/src/config/service.ts +52 -1
- package/src/config/types.ts +31 -0
- package/src/controller/controller.ts +8 -0
- package/src/core/application.ts +100 -2
- package/src/core/context.ts +1 -0
- package/src/core/server.ts +14 -0
- package/src/index.ts +81 -0
- package/src/microservice/config-center/config-center-module.ts +98 -0
- package/src/microservice/config-center/decorators.ts +159 -0
- package/src/microservice/config-center/index.ts +13 -0
- package/src/microservice/config-center/nacos-config-center.ts +126 -0
- package/src/microservice/config-center/nacos-decorators.ts +34 -0
- package/src/microservice/config-center/types.ts +80 -0
- package/src/microservice/governance/circuit-breaker.ts +229 -0
- package/src/microservice/governance/decorators.ts +113 -0
- package/src/microservice/governance/index.ts +18 -0
- package/src/microservice/governance/rate-limiter.ts +72 -0
- package/src/microservice/governance/redis-rate-limiter.ts +154 -0
- package/src/microservice/governance/retry-strategy.ts +74 -0
- package/src/microservice/governance/types.ts +247 -0
- package/src/microservice/index.ts +12 -0
- package/src/microservice/monitoring/index.ts +8 -0
- package/src/microservice/monitoring/metrics-collector.ts +223 -0
- package/src/microservice/monitoring/metrics-integration.ts +154 -0
- package/src/microservice/monitoring/types.ts +118 -0
- package/src/microservice/service-client/call-decorators.ts +107 -0
- package/src/microservice/service-client/decorators.ts +87 -0
- package/src/microservice/service-client/index.ts +37 -0
- package/src/microservice/service-client/interceptors.ts +182 -0
- package/src/microservice/service-client/load-balancer.ts +205 -0
- package/src/microservice/service-client/service-client.ts +488 -0
- package/src/microservice/service-client/types.ts +186 -0
- package/src/microservice/service-registry/decorators.ts +238 -0
- package/src/microservice/service-registry/discovery-decorators.ts +156 -0
- package/src/microservice/service-registry/health-integration.ts +146 -0
- package/src/microservice/service-registry/index.ts +20 -0
- package/src/microservice/service-registry/nacos-service-registry.ts +259 -0
- package/src/microservice/service-registry/service-registry-module.ts +105 -0
- package/src/microservice/service-registry/types.ts +149 -0
- package/src/microservice/tracing/collectors.ts +50 -0
- package/src/microservice/tracing/index.ts +15 -0
- package/src/microservice/tracing/tracer.ts +293 -0
- package/src/microservice/tracing/types.ts +213 -0
- package/src/request/request.ts +1 -0
- package/tests/config/set-value-by-path.test.ts +53 -0
- package/tests/microservice/config-center.test.ts +77 -0
- package/tests/microservice/governance.test.ts +157 -0
- package/tests/microservice/monitoring.test.ts +75 -0
- package/tests/microservice/service-client.test.ts +136 -0
- package/tests/microservice/service-registry.test.ts +80 -0
- package/tests/microservice/tracing.test.ts +143 -0
- package/tests/utils/test-port.ts +29 -19
|
@@ -93,6 +93,47 @@ const { SomeService } = await import("./some-service");
|
|
|
93
93
|
|
|
94
94
|
## 依赖注入
|
|
95
95
|
|
|
96
|
+
### ⚠️ 重要:注入的依赖为 undefined
|
|
97
|
+
|
|
98
|
+
**错误**:注入的服务在运行时为 `undefined`,或通过 `bun app.ts` 运行正常,但在 VSCode 调试器中失败。
|
|
99
|
+
|
|
100
|
+
**原因**:`tsconfig.json` 中缺少 TypeScript 装饰器元数据配置。
|
|
101
|
+
|
|
102
|
+
**解决方案**:**这非常重要!** 确保你的 `tsconfig.json` 包含以下两个选项:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"compilerOptions": {
|
|
107
|
+
"emitDecoratorMetadata": true,
|
|
108
|
+
"experimentalDecorators": true
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**为什么重要**:
|
|
114
|
+
- `emitDecoratorMetadata`:使 TypeScript 能够为装饰器发出元数据,这是依赖注入正常工作所必需的
|
|
115
|
+
- `experimentalDecorators`:启用装饰器语法支持
|
|
116
|
+
- 没有这些配置,DI 容器无法确定参数类型,将注入 `undefined`
|
|
117
|
+
|
|
118
|
+
**检查所有 tsconfig.json 文件**:
|
|
119
|
+
- 根目录的 `tsconfig.json`
|
|
120
|
+
- `examples/tsconfig.json`
|
|
121
|
+
- 任何项目特定的 `tsconfig.json` 文件
|
|
122
|
+
|
|
123
|
+
**示例**:
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"extends": "../tsconfig.json",
|
|
127
|
+
"compilerOptions": {
|
|
128
|
+
"outDir": "dist",
|
|
129
|
+
"rootDir": "./",
|
|
130
|
+
"emitDecoratorMetadata": true, // ⚠️ 必需
|
|
131
|
+
"experimentalDecorators": true // ⚠️ 必需
|
|
132
|
+
},
|
|
133
|
+
"include": ["**/*.ts"]
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
96
137
|
### 服务不可注入
|
|
97
138
|
|
|
98
139
|
**错误**:`Cannot resolve dependency` 或找不到服务。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dangao/bun-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"test": "bun test",
|
|
46
46
|
"type-check": "tsc --noEmit",
|
|
47
47
|
"clean": "rm -rf dist",
|
|
48
|
-
"bundle": "bun build src/index.ts --target=bun --format=esm --outfile=dist/index.js --external reflect-metadata --external @dangao/logsmith",
|
|
48
|
+
"bundle": "bun build src/index.ts --target=bun --format=esm --outfile=dist/index.js --external reflect-metadata --external @dangao/logsmith --external @dangao/nacos-client",
|
|
49
49
|
"dts": "tsc -p tsconfig.build.json",
|
|
50
50
|
"build": "bun run clean && bun run bundle && bun run dts",
|
|
51
|
-
"
|
|
51
|
+
"prepublishOnly": "bun run build",
|
|
52
52
|
"publish:package": "cp -r ../../README.md ../../LICENSE ../../docs . && bun publish --access public && rm -rf ./README.md ./LICENSE ./docs"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"reflect-metadata": "^0.2.2",
|
|
60
|
-
"@dangao/logsmith": "0.1.1"
|
|
60
|
+
"@dangao/logsmith": "0.1.1",
|
|
61
|
+
"@dangao/nacos-client": "0.1.0"
|
|
61
62
|
}
|
|
62
63
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../di/module';
|
|
2
|
+
import { CONFIG_CENTER_TOKEN } from '../microservice/config-center/types';
|
|
3
|
+
import type { ConfigCenter } from '../microservice/config-center/types';
|
|
4
|
+
import { ControllerRegistry } from '../controller/controller';
|
|
2
5
|
|
|
3
6
|
import { ConfigService } from './service';
|
|
4
7
|
import { CONFIG_SERVICE_TOKEN, type ConfigModuleOptions } from './types';
|
|
@@ -32,6 +35,13 @@ export class ConfigModule {
|
|
|
32
35
|
|
|
33
36
|
const service = new ConfigService(mergedConfig, options.namespace);
|
|
34
37
|
|
|
38
|
+
// 如果启用配置中心集成,延迟初始化(等待 ConfigCenterModule 注册)
|
|
39
|
+
// 初始化将在 Application.listen() 时执行,确保所有模块都已注册
|
|
40
|
+
if (options.configCenter?.enabled) {
|
|
41
|
+
// 保存配置中心选项,稍后在应用启动时初始化
|
|
42
|
+
(service as any)._configCenterOptions = options.configCenter;
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
if (options.validate) {
|
|
36
46
|
options.validate(mergedConfig);
|
|
37
47
|
}
|
|
@@ -71,6 +81,206 @@ export class ConfigModule {
|
|
|
71
81
|
}
|
|
72
82
|
return env;
|
|
73
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 初始化配置中心集成(延迟初始化,在应用启动时调用)
|
|
87
|
+
*/
|
|
88
|
+
public static async initializeConfigCenter(
|
|
89
|
+
service: ConfigService,
|
|
90
|
+
configCenterOptions: NonNullable<ConfigModuleOptions['configCenter']>,
|
|
91
|
+
): Promise<void> {
|
|
92
|
+
// 加载配置中心配置
|
|
93
|
+
const configCenterConfig = await ConfigModule.loadConfigCenterConfig(
|
|
94
|
+
configCenterOptions,
|
|
95
|
+
);
|
|
96
|
+
if (configCenterConfig) {
|
|
97
|
+
// 根据优先级合并配置
|
|
98
|
+
const currentConfig = service.getAll();
|
|
99
|
+
let updatedConfig: Record<string, unknown>;
|
|
100
|
+
if (configCenterOptions.configCenterPriority !== false) {
|
|
101
|
+
// 配置中心配置 > 环境变量 > 默认配置
|
|
102
|
+
updatedConfig = {
|
|
103
|
+
...currentConfig,
|
|
104
|
+
...configCenterConfig,
|
|
105
|
+
};
|
|
106
|
+
} else {
|
|
107
|
+
// 默认配置 > 环境变量 > 配置中心配置(配置中心配置不覆盖现有配置)
|
|
108
|
+
updatedConfig = {
|
|
109
|
+
...configCenterConfig,
|
|
110
|
+
...currentConfig,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
service.updateConfig(updatedConfig as any);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 设置配置变更监听
|
|
117
|
+
if (configCenterOptions.configs) {
|
|
118
|
+
ConfigModule.setupConfigCenterWatcher(service, configCenterOptions);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 从配置中心加载配置
|
|
124
|
+
*/
|
|
125
|
+
private static async loadConfigCenterConfig(
|
|
126
|
+
configCenterOptions: NonNullable<ConfigModuleOptions['configCenter']>,
|
|
127
|
+
retries: number = 5,
|
|
128
|
+
delay: number = 200,
|
|
129
|
+
): Promise<Record<string, unknown> | null> {
|
|
130
|
+
const container = ControllerRegistry.getInstance().getContainer();
|
|
131
|
+
|
|
132
|
+
// 重试机制:等待 ConfigCenterModule 注册完成
|
|
133
|
+
let configCenter: ConfigCenter | undefined;
|
|
134
|
+
for (let i = 0; i < retries; i++) {
|
|
135
|
+
configCenter = container.resolve<ConfigCenter>(CONFIG_CENTER_TOKEN);
|
|
136
|
+
if (configCenter) {
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
if (i < retries - 1) {
|
|
140
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!configCenter) {
|
|
145
|
+
console.warn(
|
|
146
|
+
'[ConfigModule] ConfigCenter not found after retries, skipping config center integration. ' +
|
|
147
|
+
'Make sure ConfigCenterModule is registered before ConfigModule.',
|
|
148
|
+
);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
|
|
154
|
+
if (!configCenterOptions.configs || configCenterOptions.configs.size === 0) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const configMap: Record<string, unknown> = {};
|
|
159
|
+
|
|
160
|
+
// 并行加载所有配置
|
|
161
|
+
const loadPromises: Promise<void>[] = [];
|
|
162
|
+
for (const [configPath, configInfo] of configCenterOptions.configs.entries()) {
|
|
163
|
+
loadPromises.push(
|
|
164
|
+
configCenter
|
|
165
|
+
.getConfig(
|
|
166
|
+
configInfo.dataId,
|
|
167
|
+
configInfo.groupName,
|
|
168
|
+
configInfo.namespaceId,
|
|
169
|
+
)
|
|
170
|
+
.then((result) => {
|
|
171
|
+
// 解析配置内容(支持 JSON)
|
|
172
|
+
try {
|
|
173
|
+
const parsed = JSON.parse(result.content);
|
|
174
|
+
ConfigModule.setValueByPath(configMap, configPath, parsed);
|
|
175
|
+
} catch {
|
|
176
|
+
// 如果不是 JSON,直接使用字符串值
|
|
177
|
+
ConfigModule.setValueByPath(configMap, configPath, result.content);
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
.catch((error) => {
|
|
181
|
+
console.error(
|
|
182
|
+
`[ConfigModule] Failed to load config ${configInfo.dataId}:`,
|
|
183
|
+
error,
|
|
184
|
+
);
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
await Promise.all(loadPromises);
|
|
190
|
+
|
|
191
|
+
return configMap;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('[ConfigModule] Failed to load config center config:', error);
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 设置配置中心监听器
|
|
200
|
+
*/
|
|
201
|
+
private static setupConfigCenterWatcher(
|
|
202
|
+
service: ConfigService,
|
|
203
|
+
configCenterOptions: NonNullable<ConfigModuleOptions['configCenter']>,
|
|
204
|
+
): void {
|
|
205
|
+
try {
|
|
206
|
+
const container = ControllerRegistry.getInstance().getContainer();
|
|
207
|
+
const configCenter = container.resolve<ConfigCenter>(CONFIG_CENTER_TOKEN);
|
|
208
|
+
|
|
209
|
+
if (!configCenter || !configCenterOptions.configs) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// 为每个配置设置监听器
|
|
214
|
+
for (const [configPath, configInfo] of configCenterOptions.configs.entries()) {
|
|
215
|
+
configCenter.watchConfig(
|
|
216
|
+
configInfo.dataId,
|
|
217
|
+
configInfo.groupName,
|
|
218
|
+
(result) => {
|
|
219
|
+
try {
|
|
220
|
+
// 解析配置内容
|
|
221
|
+
let parsedValue: unknown;
|
|
222
|
+
try {
|
|
223
|
+
parsedValue = JSON.parse(result.content);
|
|
224
|
+
} catch {
|
|
225
|
+
parsedValue = result.content;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 更新配置服务
|
|
229
|
+
const currentConfig = service.getAll();
|
|
230
|
+
const updatedConfig = {
|
|
231
|
+
...currentConfig,
|
|
232
|
+
};
|
|
233
|
+
ConfigModule.setValueByPath(updatedConfig, configPath, parsedValue);
|
|
234
|
+
service.updateConfig(updatedConfig as any);
|
|
235
|
+
|
|
236
|
+
console.log(
|
|
237
|
+
`[ConfigModule] Config updated: ${configPath} from ${configInfo.dataId}`,
|
|
238
|
+
);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error(
|
|
241
|
+
`[ConfigModule] Failed to update config ${configPath}:`,
|
|
242
|
+
error,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
configInfo.namespaceId,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.error(
|
|
251
|
+
'[ConfigModule] Failed to setup config center watcher:',
|
|
252
|
+
error,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 根据路径设置对象值(支持点号路径)
|
|
259
|
+
*/
|
|
260
|
+
private static setValueByPath(
|
|
261
|
+
obj: Record<string, unknown>,
|
|
262
|
+
path: string,
|
|
263
|
+
value: unknown,
|
|
264
|
+
): void {
|
|
265
|
+
const segments = path.split('.');
|
|
266
|
+
let current: Record<string, unknown> = obj;
|
|
267
|
+
|
|
268
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
269
|
+
const segment = segments[i]!;
|
|
270
|
+
// 检查是否需要创建嵌套对象
|
|
271
|
+
// 注意:typeof null === 'object',所以需要明确排除 null
|
|
272
|
+
if (
|
|
273
|
+
!(segment in current) ||
|
|
274
|
+
current[segment] == null ||
|
|
275
|
+
typeof current[segment] !== 'object'
|
|
276
|
+
) {
|
|
277
|
+
current[segment] = {};
|
|
278
|
+
}
|
|
279
|
+
current = current[segment] as Record<string, unknown>;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
current[segments[segments.length - 1]!] = value;
|
|
283
|
+
}
|
|
74
284
|
}
|
|
75
285
|
|
|
76
286
|
|
package/src/config/service.ts
CHANGED
|
@@ -3,14 +3,65 @@
|
|
|
3
3
|
* 提供类型安全的配置访问能力
|
|
4
4
|
*/
|
|
5
5
|
export class ConfigService<TConfig extends Record<string, unknown> = Record<string, unknown>> {
|
|
6
|
-
private
|
|
6
|
+
private config: TConfig;
|
|
7
7
|
private readonly namespace?: string;
|
|
8
|
+
private configUpdateListeners: Array<(config: TConfig) => void> = [];
|
|
8
9
|
|
|
9
10
|
public constructor(config: TConfig, namespace?: string) {
|
|
10
11
|
this.config = config;
|
|
11
12
|
this.namespace = namespace;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* 更新配置(用于配置中心动态刷新)
|
|
17
|
+
* @param newConfig - 新配置对象
|
|
18
|
+
*/
|
|
19
|
+
public updateConfig(newConfig: TConfig): void {
|
|
20
|
+
this.config = newConfig;
|
|
21
|
+
// 通知所有监听器
|
|
22
|
+
for (const listener of this.configUpdateListeners) {
|
|
23
|
+
try {
|
|
24
|
+
listener(newConfig);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('[ConfigService] Error in config update listener:', error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 合并配置(用于配置中心增量更新)
|
|
33
|
+
* @param partialConfig - 部分配置对象
|
|
34
|
+
*/
|
|
35
|
+
public mergeConfig(partialConfig: Partial<TConfig>): void {
|
|
36
|
+
this.config = {
|
|
37
|
+
...this.config,
|
|
38
|
+
...partialConfig,
|
|
39
|
+
} as TConfig;
|
|
40
|
+
// 通知所有监听器
|
|
41
|
+
for (const listener of this.configUpdateListeners) {
|
|
42
|
+
try {
|
|
43
|
+
listener(this.config);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('[ConfigService] Error in config update listener:', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 添加配置更新监听器
|
|
52
|
+
* @param listener - 监听器函数
|
|
53
|
+
* @returns 取消监听的函数
|
|
54
|
+
*/
|
|
55
|
+
public onConfigUpdate(listener: (config: TConfig) => void): () => void {
|
|
56
|
+
this.configUpdateListeners.push(listener);
|
|
57
|
+
return () => {
|
|
58
|
+
const index = this.configUpdateListeners.indexOf(listener);
|
|
59
|
+
if (index > -1) {
|
|
60
|
+
this.configUpdateListeners.splice(index, 1);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
14
65
|
/**
|
|
15
66
|
* 获取完整配置对象
|
|
16
67
|
*/
|
package/src/config/types.ts
CHANGED
|
@@ -20,6 +20,37 @@ export interface ConfigModuleOptions<TConfig extends Record<string, unknown> = R
|
|
|
20
20
|
* 命名空间前缀,用于逻辑分组(可选)
|
|
21
21
|
*/
|
|
22
22
|
namespace?: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 配置中心集成选项(可选)
|
|
26
|
+
*/
|
|
27
|
+
configCenter?: {
|
|
28
|
+
/**
|
|
29
|
+
* 是否启用配置中心集成
|
|
30
|
+
*/
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 配置中心配置映射
|
|
35
|
+
* key: 配置路径(如 "app.name")
|
|
36
|
+
* value: { dataId: string, groupName: string, namespaceId?: string }
|
|
37
|
+
*/
|
|
38
|
+
configs?: Map<
|
|
39
|
+
string,
|
|
40
|
+
{
|
|
41
|
+
dataId: string;
|
|
42
|
+
groupName: string;
|
|
43
|
+
namespaceId?: string;
|
|
44
|
+
}
|
|
45
|
+
>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 配置优先级
|
|
49
|
+
* 配置中心配置 > 环境变量 > 默认配置
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
configCenterPriority?: boolean;
|
|
53
|
+
};
|
|
23
54
|
}
|
|
24
55
|
|
|
25
56
|
export const CONFIG_SERVICE_TOKEN = Symbol('@dangao/bun-server:config:service');
|
|
@@ -258,6 +258,14 @@ export class ControllerRegistry {
|
|
|
258
258
|
return this.container;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
/**
|
|
262
|
+
* 获取所有已注册的控制器类
|
|
263
|
+
* @returns 控制器类数组
|
|
264
|
+
*/
|
|
265
|
+
public getAllControllers(): Constructor<unknown>[] {
|
|
266
|
+
return Array.from(this.controllerContainers.keys());
|
|
267
|
+
}
|
|
268
|
+
|
|
261
269
|
/**
|
|
262
270
|
* 获取所有已注册的控制器类
|
|
263
271
|
* @returns 控制器类数组
|
package/src/core/application.ts
CHANGED
|
@@ -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:
|
|
86
|
-
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 容器
|
package/src/core/context.ts
CHANGED
package/src/core/server.ts
CHANGED
|
@@ -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
|
@@ -306,4 +306,85 @@ export type {
|
|
|
306
306
|
SessionData,
|
|
307
307
|
RedisSessionStoreOptions,
|
|
308
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';
|
|
309
390
|
|