@be-link/shield-for-tcb-node-sdk 1.0.8 → 1.0.10

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
@@ -10,7 +10,96 @@ npm install @be-link/shield-for-tcb-node-sdk
10
10
  pnpm add @be-link/shield-for-tcb-node-sdk
11
11
  ```
12
12
 
13
- ## 使用
13
+ ## V2 SDK(推荐)
14
+
15
+ V2 SDK 从 MySQL 数据源读取配置,支持按 service + key 获取配置,并提供自动类型解析。
16
+
17
+ ### 基本使用
18
+
19
+ ```typescript
20
+ import { backendConfigServiceV2 } from '@be-link/shield-for-tcb-node-sdk'
21
+ ```
22
+
23
+ ### 获取服务列表
24
+
25
+ ```typescript
26
+ const services = await backendConfigServiceV2.getServices('local')
27
+ // 返回: ['BackendUser', 'Trade', 'User', ...]
28
+ ```
29
+
30
+ ### 获取服务的配置键列表
31
+
32
+ ```typescript
33
+ const keys = await backendConfigServiceV2.getServiceKeys('TestService', 'local')
34
+ // 返回: ['TestServiceKey1', 'TestServiceKey2', 'TestServiceKey3', ...]
35
+ ```
36
+
37
+ ### 获取单个配置
38
+
39
+ ```typescript
40
+ // 原始格式(包含元数据)
41
+ const config = await backendConfigServiceV2.fetchConfig({
42
+ service: 'TestService',
43
+ key: 'TestServiceKey1',
44
+ env: 'local'
45
+ })
46
+ // 返回: { config_key: 'TestServiceKey1', value: 'xxx', value_type: 'string', updated_at: '...' }
47
+
48
+ // 自动解析类型(推荐)
49
+ const host = await backendConfigServiceV2.getConfigValue<string>('TestService', 'TestServiceKey1', 'local')
50
+ // 返回: '127.0.0.1'
51
+
52
+ const port = await backendConfigServiceV2.getConfigValue<number>('TestService', 'TestServiceKey1', 'local')
53
+ // 返回: 1234(自动解析为数字)
54
+
55
+ const enabled = await backendConfigServiceV2.getConfigValue<boolean>('TestService', 'TestServiceKey1', 'local')
56
+ // 返回: true/false(自动解析为布尔值)
57
+
58
+ const jsonConfig = await backendConfigServiceV2.getConfigValue<object>('BackendUser', 'TestServiceKey1', 'local')
59
+ // 返回: { ... }(自动 JSON 解析)
60
+ ```
61
+
62
+ ### 批量获取配置
63
+
64
+ ```typescript
65
+ // 原始格式
66
+ const configs = await backendConfigServiceV2.fetchConfigs({
67
+ service: 'TestService',
68
+ keys: ['TestServiceKey1', 'TestServiceKey2'],
69
+ env: 'local'
70
+ })
71
+ // 返回: { 'TestServiceKey1': { value: 'xxx', value_type: 'string' }, ... }
72
+
73
+ // 自动解析类型(推荐)
74
+ const values = await backendConfigServiceV2.getConfigValues(
75
+ 'TestService',
76
+ ['TestServiceKey1', 'TestServiceKey2', 'TestServiceKey3'],
77
+ 'local'
78
+ )
79
+ // 返回: {
80
+ // }
81
+ ```
82
+
83
+ ### 环境变量
84
+
85
+ | 变量名 | 说明 | 示例 |
86
+ |--------|------|------|
87
+ | `SHIELD_SDK_HOST` | 覆盖 SDK 请求地址(本地开发用) | `http://localhost:8090` |
88
+ | `CONTAINER_ENV` | 容器环境,默认 `SCF`(云函数),设置为其他值使用内网地址 | `ECS` |
89
+ | `NODE_ENV` | 环境标识,`prod` 使用生产环境地址 | `local` / `ppe` / `prod` |
90
+
91
+ ### 本地开发
92
+
93
+ ```bash
94
+ # 设置本地服务地址
95
+ export SHIELD_SDK_HOST=http://localhost:8090
96
+ ```
97
+
98
+ ---
99
+
100
+ ## V1 SDK(旧版)
101
+
102
+ V1 SDK 从 YAML 文件读取配置,保持向后兼容。
14
103
 
15
104
  ```typescript
16
105
  import { backendConfigService, frontendConfigService } from '@be-link/shield-for-tcb-node-sdk'
@@ -21,13 +110,22 @@ const config = await backendConfigService.fetchConfig({ key: 'your-key', type: '
21
110
  // 前端使用(跳过异常处理,直接抛出原始错误)
22
111
  const frontendConfig = await frontendConfigService.fetchConfig({ key: 'your-key', type: 'json' })
23
112
 
24
- // 获取全局动态配置
25
- const globalConfig = await backendConfigService.fetchGlobalDynamicConfig()
26
-
27
- // 获取 COS 临时密钥
28
- const cosTempSecret = await backendConfigService.getCosTempSecret()
29
113
  ```
30
114
 
115
+ ---
116
+
117
+ ## V1 vs V2 对比
118
+
119
+ | 特性 | V1 SDK | V2 SDK |
120
+ |------|--------|--------|
121
+ | 数据源 | YAML 文件 | MySQL |
122
+ | 获取方式 | 按 key | 按 service + key |
123
+ | 类型解析 | 手动指定 type | 自动根据 value_type 解析 |
124
+ | 批量获取 | ❌ | ✅ |
125
+ | 配置管理 | ❌ | ✅(通过管理后台) |
126
+ | 版本追踪 | ❌ | ✅ |
127
+ | 审计日志 | ❌ | ✅ |
128
+
31
129
  ## 发布流程
32
130
 
33
131
  ### 自动发布(推荐)
package/index.d.ts CHANGED
@@ -1,2 +1,6 @@
1
1
  export { backendConfigService } from './modules/config/service';
2
2
  export type { Service as ConfigControllerTypes } from './modules/config/types';
3
+ export { backendConfigServiceV2, ConfigServiceV2 } from './modules/config/serviceV2';
4
+ export type { ServiceV2 as ConfigControllerTypesV2 } from './modules/config/typesV2';
5
+ export { ShieldConfigManager } from './modules/config/ShieldConfigManager';
6
+ export type { ShieldConfigManagerOptions, Logger } from './modules/config/ShieldConfigManager';
package/index.js CHANGED
@@ -1,5 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.backendConfigService = void 0;
3
+ exports.ShieldConfigManager = exports.ConfigServiceV2 = exports.backendConfigServiceV2 = exports.backendConfigService = void 0;
4
+ // V1 SDK (YAML 数据源)
4
5
  var service_1 = require("./modules/config/service");
5
6
  Object.defineProperty(exports, "backendConfigService", { enumerable: true, get: function () { return service_1.backendConfigService; } });
7
+ // V2 SDK (MySQL 数据源)
8
+ var serviceV2_1 = require("./modules/config/serviceV2");
9
+ Object.defineProperty(exports, "backendConfigServiceV2", { enumerable: true, get: function () { return serviceV2_1.backendConfigServiceV2; } });
10
+ Object.defineProperty(exports, "ConfigServiceV2", { enumerable: true, get: function () { return serviceV2_1.ConfigServiceV2; } });
11
+ // ShieldConfigManager
12
+ var ShieldConfigManager_1 = require("./modules/config/ShieldConfigManager");
13
+ Object.defineProperty(exports, "ShieldConfigManager", { enumerable: true, get: function () { return ShieldConfigManager_1.ShieldConfigManager; } });
@@ -9,6 +9,12 @@ export default abstract class BaseService {
9
9
  protected readonly publicDevHost = "https://ecommerce-dev.wejourney.top";
10
10
  protected readonly publicProdHost = "https://ecommerce-release.wejourney.top";
11
11
  constructor();
12
+ /** 获取 Host */
13
+ protected getHost(): string;
14
+ /** 获取 Host (V2,支持环境变量覆盖) */
15
+ protected getHostV2(): string;
12
16
  /** 获取API URL */
13
17
  protected getApiUrl(func: Function): string;
18
+ /** 获取API URL (V2,支持环境变量覆盖) */
19
+ protected getApiUrlV2(path: string): string;
14
20
  }
@@ -16,16 +16,32 @@ class BaseService {
16
16
  /** 如果是云函数环境, 默认走公网访问 */
17
17
  this.isPublicEnv = (process.env.CONTAINER_ENV || 'SCF') === 'SCF';
18
18
  }
19
- /** 获取API URL */
20
- getApiUrl(func) {
21
- const host = this.isPublicEnv
19
+ /** 获取 Host */
20
+ getHost() {
21
+ return this.isPublicEnv
22
22
  ? env_1.default.isProduction()
23
23
  ? this.publicProdHost
24
24
  : this.publicDevHost
25
25
  : env_1.default.isProduction()
26
26
  ? this.natProdHost
27
27
  : this.natDevHost;
28
- return `${host}${this.prefixUrl}/${(0, string_1.camelToKebabCase)(func.name)}`;
28
+ }
29
+ /** 获取 Host (V2,支持环境变量覆盖) */
30
+ getHostV2() {
31
+ // 支持通过环境变量覆盖 host(用于本地测试)
32
+ const overrideHost = process.env.SHIELD_SDK_HOST;
33
+ if (overrideHost) {
34
+ return overrideHost;
35
+ }
36
+ return this.getHost();
37
+ }
38
+ /** 获取API URL */
39
+ getApiUrl(func) {
40
+ return `${this.getHost()}${this.prefixUrl}/${(0, string_1.camelToKebabCase)(func.name)}`;
41
+ }
42
+ /** 获取API URL (V2,支持环境变量覆盖) */
43
+ getApiUrlV2(path) {
44
+ return `${this.getHostV2()}${this.prefixUrl}${path}`;
29
45
  }
30
46
  }
31
47
  exports.default = BaseService;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * ShieldConfigManager - SDK 级别的配置管理器
3
+ *
4
+ * 提供配置自动拉取、缓存、定时刷新功能
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // 方式一:使用单例(推荐)
9
+ * import { backendShieldConfigManager } from '@be-link/shield-for-tcb-node-sdk'
10
+ *
11
+ * await backendShieldConfigManager.setup('BackendBff', 'local')
12
+ * const config = backendShieldConfigManager.getConfig<MyConfig>()
13
+ * backendShieldConfigManager.stop()
14
+ *
15
+ * // 方式二:创建独立实例
16
+ * import { ShieldConfigManager } from '@be-link/shield-for-tcb-node-sdk'
17
+ *
18
+ * const manager = new ShieldConfigManager({
19
+ * serviceName: 'BackendBff',
20
+ * env: 'local',
21
+ * })
22
+ *
23
+ * await manager.setup()
24
+ * const config = manager.getConfig<MyConfig>()
25
+ * manager.stop()
26
+ * ```
27
+ */
28
+ export interface ShieldConfigManagerOptions {
29
+ /** 服务名称 */
30
+ serviceName: string;
31
+ /** 环境,默认取 NODE_ENV */
32
+ env?: string;
33
+ /** 刷新间隔(ms),默认 5000 */
34
+ refreshIntervalMs?: number;
35
+ /** 请求超时(ms),默认 10000 */
36
+ fetchTimeoutMs?: number;
37
+ /** 自定义日志函数,默认 console */
38
+ logger?: Logger;
39
+ }
40
+ export interface Logger {
41
+ info: (message: string, ...args: any[]) => void;
42
+ warn: (message: string, ...args: any[]) => void;
43
+ error: (message: string, ...args: any[]) => void;
44
+ }
45
+ /**
46
+ * 配置管理器
47
+ *
48
+ * 自动从 Shield 配置中心拉取服务配置,支持定时刷新和泛型类型推导
49
+ */
50
+ export declare class ShieldConfigManager<T = Record<string, any>> {
51
+ #private;
52
+ constructor(options: ShieldConfigManagerOptions);
53
+ /** 当前缓存的配置副本(原始 Record) */
54
+ get config(): Record<string, any> | null;
55
+ /** 是否已完成初始化 */
56
+ get isSetup(): boolean;
57
+ /**
58
+ * 等待初始化完成
59
+ * @returns Promise,初始化完成后 resolve
60
+ */
61
+ waitForSetup(): Promise<void>;
62
+ /**
63
+ * 初始化配置管理器,启动定时刷新
64
+ * 幂等:重复调用无效
65
+ */
66
+ setup(): Promise<void>;
67
+ /**
68
+ * 手动刷新配置(立即触发一次拉取)
69
+ */
70
+ refresh(): Promise<void>;
71
+ /**
72
+ * 获取类型化的配置
73
+ * @returns 泛型 T 类型的配置对象
74
+ */
75
+ getConfig(): T | null;
76
+ /**
77
+ * 停止定时刷新,清理资源
78
+ */
79
+ stop(): void;
80
+ }
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ /**
3
+ * ShieldConfigManager - SDK 级别的配置管理器
4
+ *
5
+ * 提供配置自动拉取、缓存、定时刷新功能
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // 方式一:使用单例(推荐)
10
+ * import { backendShieldConfigManager } from '@be-link/shield-for-tcb-node-sdk'
11
+ *
12
+ * await backendShieldConfigManager.setup('BackendBff', 'local')
13
+ * const config = backendShieldConfigManager.getConfig<MyConfig>()
14
+ * backendShieldConfigManager.stop()
15
+ *
16
+ * // 方式二:创建独立实例
17
+ * import { ShieldConfigManager } from '@be-link/shield-for-tcb-node-sdk'
18
+ *
19
+ * const manager = new ShieldConfigManager({
20
+ * serviceName: 'BackendBff',
21
+ * env: 'local',
22
+ * })
23
+ *
24
+ * await manager.setup()
25
+ * const config = manager.getConfig<MyConfig>()
26
+ * manager.stop()
27
+ * ```
28
+ */
29
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ var desc = Object.getOwnPropertyDescriptor(m, k);
32
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
33
+ desc = { enumerable: true, get: function() { return m[k]; } };
34
+ }
35
+ Object.defineProperty(o, k2, desc);
36
+ }) : (function(o, m, k, k2) {
37
+ if (k2 === undefined) k2 = k;
38
+ o[k2] = m[k];
39
+ }));
40
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
41
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
42
+ }) : function(o, v) {
43
+ o["default"] = v;
44
+ });
45
+ var __importStar = (this && this.__importStar) || (function () {
46
+ var ownKeys = function(o) {
47
+ ownKeys = Object.getOwnPropertyNames || function (o) {
48
+ var ar = [];
49
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
50
+ return ar;
51
+ };
52
+ return ownKeys(o);
53
+ };
54
+ return function (mod) {
55
+ if (mod && mod.__esModule) return mod;
56
+ var result = {};
57
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
58
+ __setModuleDefault(result, mod);
59
+ return result;
60
+ };
61
+ })();
62
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
63
+ if (kind === "m") throw new TypeError("Private method is not writable");
64
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
65
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
66
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
67
+ };
68
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
69
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
70
+ 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");
71
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
72
+ };
73
+ var _ShieldConfigManager_instances, _ShieldConfigManager_serviceName, _ShieldConfigManager_env, _ShieldConfigManager_refreshIntervalMs, _ShieldConfigManager_fetchTimeoutMs, _ShieldConfigManager_logger, _ShieldConfigManager_config, _ShieldConfigManager_refreshTimer, _ShieldConfigManager_isSetup, _ShieldConfigManager_setupPromise, _ShieldConfigManager_doSetup, _ShieldConfigManager_startRefreshTimer;
74
+ Object.defineProperty(exports, "__esModule", { value: true });
75
+ exports.ShieldConfigManager = void 0;
76
+ const serviceV2_1 = require("./serviceV2");
77
+ const shieldClient = __importStar(require("./service"));
78
+ const defaultLogger = {
79
+ info: (msg, ...args) => console.log(`[ShieldConfigManager] ${msg}`, ...args),
80
+ warn: (msg, ...args) => console.warn(`[ShieldConfigManager] ${msg}`, ...args),
81
+ error: (msg, ...args) => console.error(`[ShieldConfigManager] ${msg}`, ...args),
82
+ };
83
+ const DEFAULT_REFRESH_INTERVAL_MS = 5 * 1000;
84
+ const DEFAULT_FETCH_TIMEOUT_MS = 10 * 1000;
85
+ function withTimeout(promise, timeoutMs) {
86
+ return Promise.race([
87
+ promise,
88
+ new Promise((_resolve, reject) => setTimeout(() => reject(new Error(`ShieldConfigManager fetch timeout after ${timeoutMs}ms`)), timeoutMs)),
89
+ ]);
90
+ }
91
+ /**
92
+ * 配置管理器
93
+ *
94
+ * 自动从 Shield 配置中心拉取服务配置,支持定时刷新和泛型类型推导
95
+ */
96
+ class ShieldConfigManager {
97
+ constructor(options) {
98
+ _ShieldConfigManager_instances.add(this);
99
+ _ShieldConfigManager_serviceName.set(this, void 0);
100
+ _ShieldConfigManager_env.set(this, void 0);
101
+ _ShieldConfigManager_refreshIntervalMs.set(this, void 0);
102
+ _ShieldConfigManager_fetchTimeoutMs.set(this, void 0);
103
+ _ShieldConfigManager_logger.set(this, void 0);
104
+ _ShieldConfigManager_config.set(this, null);
105
+ _ShieldConfigManager_refreshTimer.set(this, null);
106
+ _ShieldConfigManager_isSetup.set(this, false);
107
+ _ShieldConfigManager_setupPromise.set(this, null);
108
+ if (!options.serviceName) {
109
+ throw new Error('[ShieldConfigManager] serviceName is required');
110
+ }
111
+ __classPrivateFieldSet(this, _ShieldConfigManager_serviceName, options.serviceName, "f");
112
+ __classPrivateFieldSet(this, _ShieldConfigManager_env, options.env || process.env.NODE_ENV, "f");
113
+ __classPrivateFieldSet(this, _ShieldConfigManager_refreshIntervalMs, options.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS, "f");
114
+ __classPrivateFieldSet(this, _ShieldConfigManager_fetchTimeoutMs, options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS, "f");
115
+ __classPrivateFieldSet(this, _ShieldConfigManager_logger, options.logger ?? defaultLogger, "f");
116
+ }
117
+ /** 当前缓存的配置副本(原始 Record) */
118
+ get config() {
119
+ return __classPrivateFieldGet(this, _ShieldConfigManager_config, "f");
120
+ }
121
+ /** 是否已完成初始化 */
122
+ get isSetup() {
123
+ return __classPrivateFieldGet(this, _ShieldConfigManager_isSetup, "f");
124
+ }
125
+ /**
126
+ * 等待初始化完成
127
+ * @returns Promise,初始化完成后 resolve
128
+ */
129
+ async waitForSetup() {
130
+ if (!__classPrivateFieldGet(this, _ShieldConfigManager_setupPromise, "f")) {
131
+ __classPrivateFieldSet(this, _ShieldConfigManager_setupPromise, __classPrivateFieldGet(this, _ShieldConfigManager_instances, "m", _ShieldConfigManager_doSetup).call(this), "f");
132
+ }
133
+ return __classPrivateFieldGet(this, _ShieldConfigManager_setupPromise, "f");
134
+ }
135
+ /**
136
+ * 初始化配置管理器,启动定时刷新
137
+ * 幂等:重复调用无效
138
+ */
139
+ async setup() {
140
+ if (__classPrivateFieldGet(this, _ShieldConfigManager_isSetup, "f")) {
141
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").warn('ShieldConfigManager already initialized, skipping...');
142
+ return;
143
+ }
144
+ return this.waitForSetup();
145
+ }
146
+ /**
147
+ * 手动刷新配置(立即触发一次拉取)
148
+ */
149
+ async refresh() {
150
+ try {
151
+ const config = await withTimeout(serviceV2_1.backendConfigServiceV2.fetchAllConfigs(__classPrivateFieldGet(this, _ShieldConfigManager_serviceName, "f"), __classPrivateFieldGet(this, _ShieldConfigManager_env, "f")), __classPrivateFieldGet(this, _ShieldConfigManager_fetchTimeoutMs, "f"));
152
+ if (config && Object.keys(config).length > 0) {
153
+ __classPrivateFieldSet(this, _ShieldConfigManager_config, config, "f");
154
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info('ShieldConfigManager config refreshed', { keys: Object.keys(config) });
155
+ }
156
+ else {
157
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").warn('ShieldConfigManager fetched empty config');
158
+ }
159
+ }
160
+ catch (error) {
161
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error('ShieldConfigManager refresh error', error);
162
+ }
163
+ // 兼容旧的逻辑
164
+ try {
165
+ const dynamicConfig = await withTimeout(shieldClient.backendConfigService.fetchGlobalDynamicConfig(), __classPrivateFieldGet(this, _ShieldConfigManager_fetchTimeoutMs, "f"));
166
+ if (dynamicConfig) {
167
+ process.env.authorizationTokenInside = dynamicConfig.tokenKey;
168
+ }
169
+ }
170
+ catch (error) {
171
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error('fetch dynamic config error', error);
172
+ }
173
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info('ShieldConfigManager config refreshed finally', { config: __classPrivateFieldGet(this, _ShieldConfigManager_config, "f") });
174
+ }
175
+ /**
176
+ * 获取类型化的配置
177
+ * @returns 泛型 T 类型的配置对象
178
+ */
179
+ getConfig() {
180
+ return __classPrivateFieldGet(this, _ShieldConfigManager_config, "f") ?? null;
181
+ }
182
+ /**
183
+ * 停止定时刷新,清理资源
184
+ */
185
+ stop() {
186
+ if (__classPrivateFieldGet(this, _ShieldConfigManager_refreshTimer, "f")) {
187
+ clearInterval(__classPrivateFieldGet(this, _ShieldConfigManager_refreshTimer, "f"));
188
+ __classPrivateFieldSet(this, _ShieldConfigManager_refreshTimer, null, "f");
189
+ }
190
+ __classPrivateFieldSet(this, _ShieldConfigManager_isSetup, false, "f");
191
+ __classPrivateFieldSet(this, _ShieldConfigManager_setupPromise, null, "f");
192
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info('ShieldConfigManager stopped');
193
+ }
194
+ }
195
+ exports.ShieldConfigManager = ShieldConfigManager;
196
+ _ShieldConfigManager_serviceName = new WeakMap(), _ShieldConfigManager_env = new WeakMap(), _ShieldConfigManager_refreshIntervalMs = new WeakMap(), _ShieldConfigManager_fetchTimeoutMs = new WeakMap(), _ShieldConfigManager_logger = new WeakMap(), _ShieldConfigManager_config = new WeakMap(), _ShieldConfigManager_refreshTimer = new WeakMap(), _ShieldConfigManager_isSetup = new WeakMap(), _ShieldConfigManager_setupPromise = new WeakMap(), _ShieldConfigManager_instances = new WeakSet(), _ShieldConfigManager_doSetup = async function _ShieldConfigManager_doSetup() {
197
+ try {
198
+ await this.refresh();
199
+ }
200
+ catch (error) {
201
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error('ShieldConfigManager initial refresh failed', error);
202
+ }
203
+ if (!__classPrivateFieldGet(this, _ShieldConfigManager_config, "f")) {
204
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error('ShieldConfigManager config is empty after initial refresh');
205
+ }
206
+ __classPrivateFieldGet(this, _ShieldConfigManager_instances, "m", _ShieldConfigManager_startRefreshTimer).call(this);
207
+ __classPrivateFieldSet(this, _ShieldConfigManager_isSetup, true, "f");
208
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info('ShieldConfigManager initialized successfully');
209
+ }, _ShieldConfigManager_startRefreshTimer = function _ShieldConfigManager_startRefreshTimer() {
210
+ __classPrivateFieldSet(this, _ShieldConfigManager_refreshTimer, setInterval(() => {
211
+ this.refresh().catch((error) => {
212
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error('ShieldConfigManager timer refresh error', error);
213
+ });
214
+ }, __classPrivateFieldGet(this, _ShieldConfigManager_refreshIntervalMs, "f")), "f");
215
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info(`ShieldConfigManager refresh timer started (interval: ${__classPrivateFieldGet(this, _ShieldConfigManager_refreshIntervalMs, "f")}ms)`);
216
+ };
217
+ // 导出单例
218
+ // export const backendShieldConfigManager = new ShieldConfigManager({ serviceName: '' })
@@ -15,7 +15,7 @@ class ConfigService extends BaseService_1.default {
15
15
  return (0, http_1.callApi)(this.getApiUrl(this.fetchConfig), req);
16
16
  }
17
17
  fetchGlobalDynamicConfig() {
18
- return (0, http_1.callApi)(this.getApiUrl(this.fetchGlobalDynamicConfig), undefined);
18
+ return (0, http_1.callApi)(this.getApiUrl(this.fetchGlobalDynamicConfig), undefined).catch(() => ({}));
19
19
  }
20
20
  getCosTempSecret() {
21
21
  return (0, http_1.callApi)(this.getApiUrl(this.getCosTempSecret), undefined);
@@ -0,0 +1,58 @@
1
+ import { ServiceV2 } from './typesV2';
2
+ import BaseService from '../BaseService';
3
+ /**
4
+ * V2 配置服务
5
+ * 从 MySQL 数据源读取配置,支持按 service + key 获取
6
+ */
7
+ export declare class ConfigServiceV2 extends BaseService implements ServiceV2.ConfigController {
8
+ protected prefixUrl: string;
9
+ /**
10
+ * 获取单个配置
11
+ * @param req 请求参数
12
+ * @returns 配置数据,如果配置不存在返回 null
13
+ */
14
+ fetchConfig(req: ServiceV2.Request.FetchConfig): Promise<ServiceV2.Response.FetchConfigResponse | null>;
15
+ /**
16
+ * 批量获取配置
17
+ * @param req 请求参数
18
+ * @returns 配置数据映射
19
+ */
20
+ fetchConfigs(req: ServiceV2.Request.FetchConfigs): Promise<ServiceV2.Response.FetchConfigsResponse>;
21
+ /**
22
+ * 获取所有服务列表
23
+ * @param env 环境名称(可选,默认使用当前环境)
24
+ * @returns 服务名称列表
25
+ */
26
+ getServices(env?: string): Promise<ServiceV2.Response.GetServicesResponse>;
27
+ /**
28
+ * 获取指定服务的配置键列表
29
+ * @param serviceName 服务名称
30
+ * @param env 环境名称(可选,默认使用当前环境)
31
+ * @returns 配置键列表
32
+ */
33
+ getServiceKeys(serviceName: string, env?: string): Promise<ServiceV2.Response.GetServiceKeysResponse>;
34
+ /**
35
+ * 获取配置值(自动解析类型)
36
+ * @param service 服务名称
37
+ * @param key 配置键
38
+ * @param env 环境(可选)
39
+ * @returns 解析后的配置值
40
+ */
41
+ getConfigValue<T = any>(service: string, key: string, env?: string): Promise<T | null>;
42
+ /**
43
+ * 批量获取配置值
44
+ * @param service 服务名称
45
+ * @param keys 配置键列表(可选,不传则获取该服务所有配置)
46
+ * @param env 环境(可选)
47
+ * @returns 配置值映射(服务端已自动解析类型)
48
+ */
49
+ getConfigValues<T = any>(service: string, keys?: string[], env?: string): Promise<Record<string, T>>;
50
+ /**
51
+ * 获取指定服务的所有配置
52
+ * @param service 服务名称
53
+ * @param env 环境(可选)
54
+ * @returns 该服务所有配置(Map<config_key, parsed_value> 格式)
55
+ */
56
+ fetchAllConfigs<T = any>(service: string, env?: string): Promise<Record<string, T>>;
57
+ }
58
+ export declare const backendConfigServiceV2: ConfigServiceV2;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.backendConfigServiceV2 = exports.ConfigServiceV2 = void 0;
7
+ const http_1 = require("../../utils/http");
8
+ const BaseService_1 = __importDefault(require("../BaseService"));
9
+ /**
10
+ * V2 配置服务
11
+ * 从 MySQL 数据源读取配置,支持按 service + key 获取
12
+ */
13
+ class ConfigServiceV2 extends BaseService_1.default {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.prefixUrl = '/shield/v2/config';
17
+ }
18
+ /**
19
+ * 获取单个配置
20
+ * @param req 请求参数
21
+ * @returns 配置数据,如果配置不存在返回 null
22
+ */
23
+ fetchConfig(req) {
24
+ return (0, http_1.callApi)(this.getApiUrlV2('/fetch'), req, {
25
+ skipErrorHandling: true,
26
+ }).catch(() => null);
27
+ }
28
+ /**
29
+ * 批量获取配置
30
+ * @param req 请求参数
31
+ * @returns 配置数据映射
32
+ */
33
+ fetchConfigs(req) {
34
+ return (0, http_1.callApi)(this.getApiUrlV2('/fetch-batch'), req).catch(() => ({}));
35
+ }
36
+ /**
37
+ * 获取所有服务列表
38
+ * @param env 环境名称(可选,默认使用当前环境)
39
+ * @returns 服务名称列表
40
+ */
41
+ async getServices(env) {
42
+ const query = env ? `?env=${encodeURIComponent(env)}` : '';
43
+ return (0, http_1.getApi)(this.getApiUrlV2('/services') + query).catch(() => []);
44
+ }
45
+ /**
46
+ * 获取指定服务的配置键列表
47
+ * @param serviceName 服务名称
48
+ * @param env 环境名称(可选,默认使用当前环境)
49
+ * @returns 配置键列表
50
+ */
51
+ async getServiceKeys(serviceName, env) {
52
+ const query = env ? `?env=${encodeURIComponent(env)}` : '';
53
+ return (0, http_1.getApi)(this.getApiUrlV2(`/services/${serviceName}/keys`) + query).catch(() => []);
54
+ }
55
+ /**
56
+ * 获取配置值(自动解析类型)
57
+ * @param service 服务名称
58
+ * @param key 配置键
59
+ * @param env 环境(可选)
60
+ * @returns 解析后的配置值
61
+ */
62
+ async getConfigValue(service, key, env) {
63
+ const result = await this.fetchConfig({ service, key, env });
64
+ if (!result) {
65
+ return null;
66
+ }
67
+ // 根据类型解析值
68
+ switch (result.value_type) {
69
+ case 'number':
70
+ return Number(result.value);
71
+ case 'boolean':
72
+ return (result.value === 'true' || result.value === '1');
73
+ case 'object':
74
+ case 'array':
75
+ try {
76
+ return JSON.parse(result.value);
77
+ }
78
+ catch {
79
+ return result.value;
80
+ }
81
+ default:
82
+ return result.value;
83
+ }
84
+ }
85
+ /**
86
+ * 批量获取配置值
87
+ * @param service 服务名称
88
+ * @param keys 配置键列表(可选,不传则获取该服务所有配置)
89
+ * @param env 环境(可选)
90
+ * @returns 配置值映射(服务端已自动解析类型)
91
+ */
92
+ async getConfigValues(service, keys, env) {
93
+ return this.fetchConfigs({ service, keys, env });
94
+ }
95
+ /**
96
+ * 获取指定服务的所有配置
97
+ * @param service 服务名称
98
+ * @param env 环境(可选)
99
+ * @returns 该服务所有配置(Map<config_key, parsed_value> 格式)
100
+ */
101
+ async fetchAllConfigs(service, env) {
102
+ return this.fetchConfigs({ service, env });
103
+ }
104
+ }
105
+ exports.ConfigServiceV2 = ConfigServiceV2;
106
+ // 导出单例
107
+ exports.backendConfigServiceV2 = new ConfigServiceV2();
@@ -0,0 +1,106 @@
1
+ export declare namespace ServiceV2 {
2
+ namespace Entity {
3
+ /**
4
+ * 配置项
5
+ */
6
+ interface ConfigItem {
7
+ config_key: string;
8
+ value: string;
9
+ value_type: 'string' | 'number' | 'boolean' | 'object' | 'array';
10
+ updated_at: string;
11
+ }
12
+ /**
13
+ * 批量配置项
14
+ */
15
+ interface BatchConfigItem {
16
+ value: string;
17
+ value_type: 'string' | 'number' | 'boolean' | 'object' | 'array';
18
+ }
19
+ }
20
+ namespace Request {
21
+ /**
22
+ * 获取单个配置请求参数
23
+ */
24
+ interface FetchConfig {
25
+ service: string;
26
+ key: string;
27
+ env?: string;
28
+ }
29
+ /**
30
+ * 批量获取配置请求参数
31
+ */
32
+ interface FetchConfigs {
33
+ service: string;
34
+ keys?: string[];
35
+ env?: string;
36
+ }
37
+ /**
38
+ * 获取服务列表请求参数
39
+ */
40
+ interface GetServices {
41
+ env?: string;
42
+ }
43
+ /**
44
+ * 获取服务配置键列表请求参数
45
+ */
46
+ interface GetServiceKeys {
47
+ serviceName: string;
48
+ env?: string;
49
+ }
50
+ }
51
+ namespace Response {
52
+ /**
53
+ * 获取单个配置响应
54
+ */
55
+ interface FetchConfigResponse {
56
+ config_key: string;
57
+ value: string;
58
+ value_type: 'string' | 'number' | 'boolean' | 'object' | 'array';
59
+ updated_at: string;
60
+ }
61
+ /**
62
+ * 批量获取配置响应
63
+ * 返回 Map<config_key, parsed_value> 格式
64
+ * value 会自动解析:JSON 对象/数组会解析,其他返回原始字符串
65
+ */
66
+ type FetchConfigsResponse = Record<string, any>;
67
+ /**
68
+ * 获取服务列表响应
69
+ */
70
+ type GetServicesResponse = string[];
71
+ /**
72
+ * 获取服务配置键列表响应
73
+ */
74
+ type GetServiceKeysResponse = string[];
75
+ }
76
+ /**
77
+ * V2 配置控制器接口
78
+ */
79
+ interface ConfigController {
80
+ /**
81
+ * 获取单个配置
82
+ * @param req 请求参数
83
+ * @returns 配置数据
84
+ */
85
+ fetchConfig(req: Request.FetchConfig): Promise<Response.FetchConfigResponse | null>;
86
+ /**
87
+ * 批量获取配置
88
+ * @param req 请求参数
89
+ * @returns 配置数据映射
90
+ */
91
+ fetchConfigs(req: Request.FetchConfigs): Promise<Response.FetchConfigsResponse>;
92
+ /**
93
+ * 获取所有服务列表
94
+ * @param env 环境名称
95
+ * @returns 服务列表
96
+ */
97
+ getServices(env?: string): Promise<Response.GetServicesResponse>;
98
+ /**
99
+ * 获取指定服务的配置键列表
100
+ * @param serviceName 服务名称
101
+ * @param env 环境名称
102
+ * @returns 配置键列表
103
+ */
104
+ getServiceKeys(serviceName: string, env?: string): Promise<Response.GetServiceKeysResponse>;
105
+ }
106
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@be-link/shield-for-tcb-node-sdk",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "ShieldForTCB Node.js SDK",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/utils/http.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  type CallApiOptions = {
2
2
  skipErrorHandling?: boolean;
3
3
  };
4
+ type GetApiOptions = {
5
+ skipErrorHandling?: boolean;
6
+ };
4
7
  export declare function callApi<T extends (args: any) => Promise<any>>(url: string, request?: Parameters<T>[0], options?: CallApiOptions): Promise<Awaited<ReturnType<T>>>;
8
+ /**
9
+ * GET 请求 API
10
+ */
11
+ export declare function getApi<T extends (args: any) => Promise<any>>(url: string, options?: GetApiOptions): Promise<Awaited<ReturnType<T>>>;
5
12
  export {};
package/utils/http.js CHANGED
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.callApi = callApi;
40
+ exports.getApi = getApi;
40
41
  const axios_1 = __importDefault(require("axios"));
41
42
  const uuid_1 = require("uuid");
42
43
  const axios_retry_1 = __importDefault(require("axios-retry"));
@@ -99,3 +100,33 @@ async function callApi(url, request, options) {
99
100
  throw error;
100
101
  }
101
102
  }
103
+ /**
104
+ * GET 请求 API
105
+ */
106
+ async function getApi(url, options) {
107
+ const requestId = (0, uuid_1.v4)();
108
+ try {
109
+ console.info(`准备发起shield-for-tcb GET请求[${requestId}]: ${url}`);
110
+ const response = await axios_1.default.get(url, {
111
+ headers: { 'x-request-id': requestId, 'content-type': 'application/json' },
112
+ });
113
+ const responseData = response.data;
114
+ return responseData.data;
115
+ }
116
+ catch (error) {
117
+ if (options?.skipErrorHandling) {
118
+ throw error;
119
+ }
120
+ const axiosError = error;
121
+ if (axiosError.response) {
122
+ const response = axiosError.response;
123
+ const data = response.data;
124
+ console.error(`shield-for-tcb GET异常: ${axiosError.message}, requestId: ${requestId}`);
125
+ console.info('响应信息', data.message);
126
+ console.error('异常堆栈', JSON.stringify(error.stack));
127
+ throw axiosError;
128
+ }
129
+ console.error(`shield-for-tcb GET未知异常: ${axiosError.message}`, error.stack);
130
+ throw error;
131
+ }
132
+ }