@be-link/shield-for-tcb-node-sdk 1.0.12 → 1.0.14
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
CHANGED
|
@@ -126,6 +126,68 @@ const frontendConfig = await frontendConfigService.fetchConfig({ key: 'your-key'
|
|
|
126
126
|
| 版本追踪 | ❌ | ✅ |
|
|
127
127
|
| 审计日志 | ❌ | ✅ |
|
|
128
128
|
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## ShieldConfigManager(配置管理器)
|
|
132
|
+
|
|
133
|
+
`ShieldConfigManager` 提供配置自动拉取、缓存、定时刷新功能,适合需要持续使用配置的服务。
|
|
134
|
+
|
|
135
|
+
### 使用方式
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { ShieldConfigManager } from '@be-link/shield-for-tcb-node-sdk'
|
|
139
|
+
|
|
140
|
+
const manager = new ShieldConfigManager({
|
|
141
|
+
serviceName: 'BackendBff',
|
|
142
|
+
env: 'local',
|
|
143
|
+
enableInfoLog: true, // 可选,默认 false
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
await manager.setup()
|
|
147
|
+
const config = manager.getConfig<MyConfig>()
|
|
148
|
+
manager.stop()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 配置参数
|
|
152
|
+
|
|
153
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
154
|
+
|------|------|--------|------|
|
|
155
|
+
| `serviceName` | `string` | **必填** | 服务名称 |
|
|
156
|
+
| `env` | `string` | `NODE_ENV` | 环境 |
|
|
157
|
+
| `refreshIntervalMs` | `number` | `5000` | 刷新间隔(毫秒) |
|
|
158
|
+
| `fetchTimeoutMs` | `number` | `10000` | 请求超时(毫秒) |
|
|
159
|
+
| `enableInfoLog` | `boolean` | `false` | 是否打印 info 日志 |
|
|
160
|
+
| `logger` | `Logger` | `console` | 自定义日志函数 |
|
|
161
|
+
|
|
162
|
+
### 日志说明
|
|
163
|
+
|
|
164
|
+
`enableInfoLog` 默认为 `false`,不打印 info 级别日志。设置为 `true` 时会打印以下日志:
|
|
165
|
+
|
|
166
|
+
- 初始化成功
|
|
167
|
+
- 配置刷新(包含配置的 key 列表)
|
|
168
|
+
- 配置最终内容
|
|
169
|
+
- 定时器启动信息
|
|
170
|
+
- 停止信息
|
|
171
|
+
|
|
172
|
+
error 级别日志不受 `enableInfoLog` 影响,始终打印:
|
|
173
|
+
|
|
174
|
+
- 初始刷新失败
|
|
175
|
+
- 配置为空警告
|
|
176
|
+
- 刷新错误
|
|
177
|
+
- 定时器刷新错误
|
|
178
|
+
|
|
179
|
+
### API
|
|
180
|
+
|
|
181
|
+
| 方法 | 说明 |
|
|
182
|
+
|------|------|
|
|
183
|
+
| `setup()` | 初始化并启动定时刷新,幂等操作 |
|
|
184
|
+
| `getConfig<T>()` | 获取类型化的配置对象 |
|
|
185
|
+
| `refresh()` | 手动触发一次配置刷新 |
|
|
186
|
+
| `stop()` | 停止定时刷新,清理资源 |
|
|
187
|
+
| `waitForSetup()` | 等待初始化完成 |
|
|
188
|
+
| `isSetup` | 是否已完成初始化(只读属性) |
|
|
189
|
+
| `config` | 当前缓存的配置(原始 Record,只读属性) |
|
|
190
|
+
|
|
129
191
|
## 发布流程
|
|
130
192
|
|
|
131
193
|
### 自动发布(推荐)
|
|
@@ -45,6 +45,32 @@ export interface Logger {
|
|
|
45
45
|
warn: (message: string, ...args: any[]) => void;
|
|
46
46
|
error: (message: string, ...args: any[]) => void;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* 流量控制配置
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```json
|
|
53
|
+
* {
|
|
54
|
+
* "enabled": true,
|
|
55
|
+
* "totalBuckets": 100,
|
|
56
|
+
* "effectiveBuckets": 10,
|
|
57
|
+
* "whitelist": ["user_001", "user_002"],
|
|
58
|
+
* "blacklist": ["test_*"]
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export interface TrafficControlConfig {
|
|
63
|
+
/** 总开关 */
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
/** 总桶数 */
|
|
66
|
+
totalBuckets: number;
|
|
67
|
+
/** 生效桶数(bucket 0 到 effectiveBuckets-1 生效) */
|
|
68
|
+
effectiveBuckets: number;
|
|
69
|
+
/** 白名单(命中后视为生效) */
|
|
70
|
+
whitelist?: string[];
|
|
71
|
+
/** 黑名单(命中后视为不生效) */
|
|
72
|
+
blacklist?: string[];
|
|
73
|
+
}
|
|
48
74
|
/**
|
|
49
75
|
* 配置管理器
|
|
50
76
|
*
|
|
@@ -76,6 +102,52 @@ export declare class ShieldConfigManager<T = Record<string, any>> {
|
|
|
76
102
|
* @returns 泛型 T 类型的配置对象
|
|
77
103
|
*/
|
|
78
104
|
getConfig(): T | null;
|
|
105
|
+
/**
|
|
106
|
+
* 根据 config_key 获取对应的配置值
|
|
107
|
+
* @param key 配置键名(如 'REDIS', 'SQL')
|
|
108
|
+
* @param defaultValue 默认值(可选)
|
|
109
|
+
* @returns 配置值,如果不存在则返回默认值或 undefined
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* // 获取配置
|
|
113
|
+
* const port = manager.getValue('API_PORT', 8090)
|
|
114
|
+
*
|
|
115
|
+
* // 获取配置并指定类型
|
|
116
|
+
* const isEnabled = manager.getValue<boolean>('FEATURE.ENABLED', false)
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
getValue<T = string>(key: string, defaultValue?: T): T | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* 根据 config_key 获取开关状态(布尔值)
|
|
122
|
+
* @param key 配置键名
|
|
123
|
+
* @param defaultValue 默认值(可选),默认为 false
|
|
124
|
+
* @returns 开关状态,true 表示开启,false 表示关闭
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* // 检查功能是否开启
|
|
128
|
+
* const isEnabled = manager.isSwitchEnabled('FEATURE.ENABLED')
|
|
129
|
+
*
|
|
130
|
+
* // 指定默认值为 true
|
|
131
|
+
* const isDebug = manager.isSwitchEnabled('DEBUG_MODE', true)
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
isSwitchEnabled(key: string, defaultValue?: boolean): boolean;
|
|
135
|
+
/**
|
|
136
|
+
* 判断请求是否命中灰度流量
|
|
137
|
+
* @param configKey 配置键名(如 'TRAFFIC_SPLIT')
|
|
138
|
+
* @param identifier 路由标识(如用户ID)
|
|
139
|
+
* @param defaultValue 默认值(可选),默认为 false
|
|
140
|
+
* @returns 是否命中灰度流量
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* // 检查用户是否命中灰度流量
|
|
144
|
+
* const isHit = manager.isHitGrey('TRAFFIC_SPLIT', userId, false)
|
|
145
|
+
* if (isHit) {
|
|
146
|
+
* // 灰度流量
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
isHitGrey(configKey: string, identifier: string, defaultValue?: boolean): boolean;
|
|
79
151
|
/**
|
|
80
152
|
* 停止定时刷新,清理资源
|
|
81
153
|
*/
|
|
@@ -71,7 +71,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
71
71
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
72
72
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
73
73
|
};
|
|
74
|
-
var _ShieldConfigManager_instances, _ShieldConfigManager_serviceName, _ShieldConfigManager_env, _ShieldConfigManager_refreshIntervalMs, _ShieldConfigManager_fetchTimeoutMs, _ShieldConfigManager_enableInfoLog, _ShieldConfigManager_logger, _ShieldConfigManager_config, _ShieldConfigManager_refreshTimer, _ShieldConfigManager_isSetup, _ShieldConfigManager_setupPromise, _ShieldConfigManager_doSetup, _ShieldConfigManager_startRefreshTimer;
|
|
74
|
+
var _ShieldConfigManager_instances, _ShieldConfigManager_serviceName, _ShieldConfigManager_env, _ShieldConfigManager_refreshIntervalMs, _ShieldConfigManager_fetchTimeoutMs, _ShieldConfigManager_enableInfoLog, _ShieldConfigManager_logger, _ShieldConfigManager_config, _ShieldConfigManager_refreshTimer, _ShieldConfigManager_isSetup, _ShieldConfigManager_setupPromise, _ShieldConfigManager_doSetup, _ShieldConfigManager_hashString, _ShieldConfigManager_startRefreshTimer;
|
|
75
75
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
76
76
|
exports.ShieldConfigManager = void 0;
|
|
77
77
|
const serviceV2_1 = require("./serviceV2");
|
|
@@ -183,6 +183,108 @@ class ShieldConfigManager {
|
|
|
183
183
|
getConfig() {
|
|
184
184
|
return __classPrivateFieldGet(this, _ShieldConfigManager_config, "f") ?? null;
|
|
185
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* 根据 config_key 获取对应的配置值
|
|
188
|
+
* @param key 配置键名(如 'REDIS', 'SQL')
|
|
189
|
+
* @param defaultValue 默认值(可选)
|
|
190
|
+
* @returns 配置值,如果不存在则返回默认值或 undefined
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* // 获取配置
|
|
194
|
+
* const port = manager.getValue('API_PORT', 8090)
|
|
195
|
+
*
|
|
196
|
+
* // 获取配置并指定类型
|
|
197
|
+
* const isEnabled = manager.getValue<boolean>('FEATURE.ENABLED', false)
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
getValue(key, defaultValue) {
|
|
201
|
+
if (!__classPrivateFieldGet(this, _ShieldConfigManager_config, "f")) {
|
|
202
|
+
return defaultValue;
|
|
203
|
+
}
|
|
204
|
+
const value = __classPrivateFieldGet(this, _ShieldConfigManager_config, "f")[key];
|
|
205
|
+
if (value === undefined || value === null) {
|
|
206
|
+
return defaultValue;
|
|
207
|
+
}
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* 根据 config_key 获取开关状态(布尔值)
|
|
212
|
+
* @param key 配置键名
|
|
213
|
+
* @param defaultValue 默认值(可选),默认为 false
|
|
214
|
+
* @returns 开关状态,true 表示开启,false 表示关闭
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* // 检查功能是否开启
|
|
218
|
+
* const isEnabled = manager.isSwitchEnabled('FEATURE.ENABLED')
|
|
219
|
+
*
|
|
220
|
+
* // 指定默认值为 true
|
|
221
|
+
* const isDebug = manager.isSwitchEnabled('DEBUG_MODE', true)
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
isSwitchEnabled(key, defaultValue = false) {
|
|
225
|
+
if (!__classPrivateFieldGet(this, _ShieldConfigManager_config, "f")) {
|
|
226
|
+
return defaultValue;
|
|
227
|
+
}
|
|
228
|
+
const value = __classPrivateFieldGet(this, _ShieldConfigManager_config, "f")[key];
|
|
229
|
+
if (value === undefined || value === null) {
|
|
230
|
+
return defaultValue;
|
|
231
|
+
}
|
|
232
|
+
// 支持多种布尔值表示
|
|
233
|
+
if (typeof value === 'boolean') {
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
if (typeof value === 'number') {
|
|
237
|
+
return value !== 0;
|
|
238
|
+
}
|
|
239
|
+
if (typeof value === 'string') {
|
|
240
|
+
const lower = value.toLowerCase();
|
|
241
|
+
if (lower === 'true' || lower === '1' || lower === 'yes' || lower === 'on') {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (lower === 'false' || lower === '0' || lower === 'no' || lower === 'off') {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return defaultValue;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 判断请求是否命中灰度流量
|
|
252
|
+
* @param configKey 配置键名(如 'TRAFFIC_SPLIT')
|
|
253
|
+
* @param identifier 路由标识(如用户ID)
|
|
254
|
+
* @param defaultValue 默认值(可选),默认为 false
|
|
255
|
+
* @returns 是否命中灰度流量
|
|
256
|
+
* @example
|
|
257
|
+
* ```ts
|
|
258
|
+
* // 检查用户是否命中灰度流量
|
|
259
|
+
* const isHit = manager.isHitGrey('TRAFFIC_SPLIT', userId, false)
|
|
260
|
+
* if (isHit) {
|
|
261
|
+
* // 灰度流量
|
|
262
|
+
* }
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
isHitGrey(configKey, identifier, defaultValue = false) {
|
|
266
|
+
const config = this.getValue(configKey);
|
|
267
|
+
if (!config) {
|
|
268
|
+
return defaultValue;
|
|
269
|
+
}
|
|
270
|
+
// 总开关关闭,返回 false
|
|
271
|
+
if (!config.enabled) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
// 黑名单检查(精确匹配)- 命中后返回 false
|
|
275
|
+
if (config.blacklist && config.blacklist.includes(identifier)) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
// 白名单检查(精确匹配)- 命中后返回 true
|
|
279
|
+
if (config.whitelist && config.whitelist.includes(identifier)) {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
// 桶路由
|
|
283
|
+
const totalBuckets = config.totalBuckets || 100;
|
|
284
|
+
const effectiveBuckets = config.effectiveBuckets || 0;
|
|
285
|
+
const hash = __classPrivateFieldGet(this, _ShieldConfigManager_instances, "m", _ShieldConfigManager_hashString).call(this, identifier);
|
|
286
|
+
return hash % totalBuckets < effectiveBuckets;
|
|
287
|
+
}
|
|
186
288
|
/**
|
|
187
289
|
* 停止定时刷新,清理资源
|
|
188
290
|
*/
|
|
@@ -210,6 +312,14 @@ _ShieldConfigManager_serviceName = new WeakMap(), _ShieldConfigManager_env = new
|
|
|
210
312
|
__classPrivateFieldGet(this, _ShieldConfigManager_instances, "m", _ShieldConfigManager_startRefreshTimer).call(this);
|
|
211
313
|
__classPrivateFieldSet(this, _ShieldConfigManager_isSetup, true, "f");
|
|
212
314
|
__classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info('ShieldConfigManager initialized successfully');
|
|
315
|
+
}, _ShieldConfigManager_hashString = function _ShieldConfigManager_hashString(str) {
|
|
316
|
+
let hash = 0;
|
|
317
|
+
for (let i = 0; i < str.length; i++) {
|
|
318
|
+
const char = str.charCodeAt(i);
|
|
319
|
+
hash = (hash << 5) - hash + char;
|
|
320
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
321
|
+
}
|
|
322
|
+
return Math.abs(hash);
|
|
213
323
|
}, _ShieldConfigManager_startRefreshTimer = function _ShieldConfigManager_startRefreshTimer() {
|
|
214
324
|
__classPrivateFieldSet(this, _ShieldConfigManager_refreshTimer, setInterval(() => {
|
|
215
325
|
this.refresh().catch((error) => {
|